diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..f4a3ef70 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# CHANGELOG + +## v0.2.34 - 2025-04-25 + +Added option to show dependency graph and repaired issue #623 diff --git a/build.sbt b/build.sbt index 42855d7f..83d33ccb 100644 --- a/build.sbt +++ b/build.sbt @@ -1,13 +1,13 @@ -lazy val scala212 = "2.12.17" -lazy val scala213 = "2.13.10" -lazy val scala3 = "3.2.1" +lazy val scala212 = "2.12.20" +lazy val scala213 = "2.13.15" +lazy val scala3 = "3.6.3" lazy val supportedScalaVersions = List( - scala3, + scala212, scala213, - scala212 + scala3 ) -val Java11 = JavaSpec.temurin("11") +val Java11 = JavaSpec.temurin("11") lazy val srdfVersion = "0.1.125" lazy val utilsVersion = "0.2.25" @@ -19,7 +19,7 @@ lazy val catsVersion = "2.9.0" lazy val catsEffectVersion = "3.4.4" lazy val circeVersion = "0.14.2" lazy val commonsTextVersion = "1.8" -lazy val declineVersion = "2.4.1" +lazy val declineVersion = "2.5.0" lazy val fansiVersion = "0.3.0" lazy val fs2Version = "3.4.0" lazy val jenaVersion = "4.3.2" @@ -73,7 +73,6 @@ lazy val wdtkUtil = "org.wikidata.wdtk" % "wdtk-util" % wikidataToolkitVersion lazy val scalacheck = "org.scalacheck" %% "scalacheck" % scalacheckVersion lazy val typesafeConfig = "com.typesafe" % "config" % typesafeConfigVersion - lazy val logbackClassic = "ch.qos.logback" % "logback-classic" % logbackVersion lazy val scalaLogging = "com.typesafe.scala-logging" %% "scala-logging" % scalaLoggingVersion @@ -142,8 +141,8 @@ lazy val shexs = project catsEffect, decline, declineEffect, - slf4jAPI, - slf4jSimple, + // slf4jAPI, + // slf4jSimple, srdf, srdf4j, srdfJena, @@ -252,7 +251,7 @@ lazy val wshex = project .settings( crossScalaVersions := supportedScalaVersions, libraryDependencies ++= Seq( - utils, + utils, catsCore, catsKernel, circeCore, @@ -269,7 +268,7 @@ lazy val wshex = project scalaCollCompat, srdfJena, munit % Test, - munitEffect % Test, + munitEffect % Test ), testFrameworks += new TestFramework("munit.Framework") ) @@ -580,6 +579,8 @@ lazy val commonSettings = compilationSettings ++ sharedDependencies ++ Seq( email = "jelabra@gmail.com", url = url("https://weso.labra.es") ) - ), - libraryDependencies += compilerPlugin("com.github.ghik" % "zerowaste" % "0.2.1" cross CrossVersion.full) + ) + /*libraryDependencies += compilerPlugin( + ("com.github.ghik" % "zerowaste" % "1.0.0").cross(CrossVersion.full) + )*/ ) ++ warnUnusedImport diff --git a/examples/non_stratified.shex b/examples/non_stratified.shex new file mode 100644 index 00000000..50bffd22 --- /dev/null +++ b/examples/non_stratified.shex @@ -0,0 +1,3 @@ +prefix : + +:S { :p NOT @:S } \ No newline at end of file diff --git a/examples/positive_recursion.shex b/examples/positive_recursion.shex new file mode 100644 index 00000000..ae0916af --- /dev/null +++ b/examples/positive_recursion.shex @@ -0,0 +1,4 @@ +prefix : + +# Positive recursion +:S { :p @:S +; :p .* } OR [ :d ] diff --git a/examples/separation.shex b/examples/separation.shex new file mode 100644 index 00000000..ae95e14a --- /dev/null +++ b/examples/separation.shex @@ -0,0 +1,5 @@ +prefix : + +# Separation test +:S { :p @:S + } +:S1 NOT @:S \ No newline at end of file diff --git a/examples/separation1.shex b/examples/separation1.shex new file mode 100644 index 00000000..e6a66b7d --- /dev/null +++ b/examples/separation1.shex @@ -0,0 +1,4 @@ +prefix : + +# Separation test 1 +:S { :p @:S + } diff --git a/examples/separation2.shex b/examples/separation2.shex new file mode 100644 index 00000000..e6a66b7d --- /dev/null +++ b/examples/separation2.shex @@ -0,0 +1,4 @@ +prefix : + +# Separation test 1 +:S { :p @:S + } diff --git a/examples/separation4.shex b/examples/separation4.shex new file mode 100644 index 00000000..ae95e14a --- /dev/null +++ b/examples/separation4.shex @@ -0,0 +1,5 @@ +prefix : + +# Separation test +:S { :p @:S + } +:S1 NOT @:S \ No newline at end of file diff --git a/modules/depGraphs/src/main/scala/es/weso/depgraphs/DepGraph.scala b/modules/depGraphs/src/main/scala/es/weso/depgraphs/DepGraph.scala index 9900fb1f..60748ba9 100644 --- a/modules/depGraphs/src/main/scala/es/weso/depgraphs/DepGraph.scala +++ b/modules/depGraphs/src/main/scala/es/weso/depgraphs/DepGraph.scala @@ -48,10 +48,10 @@ trait DepGraph[Node] { private def haveNegativeLink(node1: Node, node2: Node): Boolean = edgeBetween(node1, node2) match { - case Some(Neg) => true - case Some(Pos) => false - case Some(Both) => true - case None => false + case Some(Neg) => true + case Some(Pos) => false + // case Some(Both) => true + case None => false } def showEdges(showNode: Node => String = x => x.toString): String diff --git a/modules/depGraphs/src/main/scala/es/weso/depgraphs/DepGraphJGraphT.scala b/modules/depGraphs/src/main/scala/es/weso/depgraphs/DepGraphJGraphT.scala index 5841a281..a33e466d 100644 --- a/modules/depGraphs/src/main/scala/es/weso/depgraphs/DepGraphJGraphT.scala +++ b/modules/depGraphs/src/main/scala/es/weso/depgraphs/DepGraphJGraphT.scala @@ -46,7 +46,7 @@ case class DepGraphJGraphT[Node]() extends DepGraph[Node] with LazyLogging { // if (!graph.containsVertex(node)) graph.addVertex(node) - private def addEdge(node1: Node, node2: Node, edge: Edge): DepGraph[Node] = { + private def addEdgeInternal(node1: Node, node2: Node, edge: Edge): DepGraph[Node] = { checkVertex(node1) checkVertex(node2) graph.addEdge(node1, node2, edge) @@ -61,14 +61,19 @@ case class DepGraphJGraphT[Node]() extends DepGraph[Node] with LazyLogging { checkVertex(node2) this.edgeBetween(node1, node2) match { case Some(pn) => + // println(s"Edge between $node1 and $node2 already exists with posNeg $pn") removeEdge(node1, node2) - addEdge(node1, node2, Edge(node1, pn.combine(posNeg), node2)) - case None => addEdge(node1, node2, Edge(node1, posNeg, node2)) + val newPosNeg = pn.combine(posNeg) + val result = addEdgeInternal(node1, node2, Edge(node1, newPosNeg, node2)) + // println(s"New edge added $node1 and $node2 posNeg $newPosNeg") + result + case None => addEdgeInternal(node1, node2, Edge(node1, posNeg, node2)) } } override def edgeBetween(node1: Node, node2: Node): Option[PosNeg] = { - val outEdges = graph.edgesOf(node1).asScala.toSet + val outEdges: Set[Edge] = graph.outgoingEdgesOf(node1).asScala.toSet + // println(s"outEdges($node1)=$outEdges") outEdges.collect { case e: Edge if e.target == node2 => e.posNeg }.headOption } @@ -89,7 +94,7 @@ case class DepGraphJGraphT[Node]() extends DepGraph[Node] with LazyLogging { } private def containsNegEdge(g: Graph[Node, Edge]): Boolean = - g.edgeSet.asScala.exists(e => e.posNeg == Neg || e.posNeg == Both) + g.edgeSet.asScala.exists(e => e.posNeg == Neg) // || e.posNeg == Both) override def negCycles: Set[Set[(Node, Node)]] = { val scAlg: StrongConnectivityAlgorithm[Node, Edge] = @@ -112,9 +117,9 @@ case class DepGraphJGraphT[Node]() extends DepGraph[Node] with LazyLogging { def showPosNeg(pn: PosNeg): String = pn match { - case Pos => "-(+)->" - case Neg => "-(-)->" - case Both => "-(-/+)->" + case Pos => "-(+)->" + case Neg => "-(-)->" + // case Both => "-(-/+)->" } def showEdges(showNode: Node => String): String = { diff --git a/modules/depGraphs/src/main/scala/es/weso/depgraphs/PosNeg.scala b/modules/depGraphs/src/main/scala/es/weso/depgraphs/PosNeg.scala index 36ef3a53..b19e228c 100644 --- a/modules/depGraphs/src/main/scala/es/weso/depgraphs/PosNeg.scala +++ b/modules/depGraphs/src/main/scala/es/weso/depgraphs/PosNeg.scala @@ -2,27 +2,29 @@ package es.weso.depgraphs sealed trait PosNeg { def change: PosNeg = this match { - case Neg => Pos - case Pos => Neg - case Both => Both + case Neg => Pos + case Pos => Neg + // case Both => Both } def combine(other: PosNeg): PosNeg } case object Pos extends PosNeg { override def combine(other: PosNeg): PosNeg = other match { - case Pos => Pos - case Neg => Both - case Both => Both + case Pos => Pos + case Neg => Neg + // case Neg => Both + // case Both => Both } } case object Neg extends PosNeg { override def combine(other: PosNeg): PosNeg = other match { - case Pos => Both - case Neg => Neg - case Both => Both + case Pos => Neg // Both + case Neg => Neg + // case Both => Both } } -case object Both extends PosNeg { + +/*case object Both extends PosNeg { override def combine(other: PosNeg): PosNeg = Both -} +}*/ diff --git a/modules/shex/src/main/scala/es/weso/shex/Dependencies.scala b/modules/shex/src/main/scala/es/weso/shex/Dependencies.scala index 7a5d77a6..ff6c3f7e 100644 --- a/modules/shex/src/main/scala/es/weso/shex/Dependencies.scala +++ b/modules/shex/src/main/scala/es/weso/shex/Dependencies.scala @@ -22,14 +22,14 @@ object Dependencies { * If the set is empy, there are no negated cycles. */ def negCycles(schema: Schema): ES[Set[Set[(ShapeLabel, ShapeLabel)]]] = - depGraph(schema).map(_.negCycles) + schema.depGraph.map(_.negCycles) def oddNegCycles(schema: Schema): ES[Set[Set[(ShapeLabel, ShapeLabel)]]] = - depGraph(schema).map(_.oddNegCycles) - /* for { - dg <- depGraph(schema) - negCycles = dg.negCycles.filter { nc => dg.countNegLinks(nc) % 2 == 1 } - } yield negCycles */ + // depGraph(schema).map(_.oddNegCycles) + for { + dg <- schema.depGraph + negCycles = dg.negCycles.filter(nc => dg.countNegLinks(nc) % 2 == 1) + } yield negCycles /** Returns the dependency graph of a schema * @@ -42,7 +42,11 @@ object Dependencies { case None => emptyGraph case Some(shapes) => shapes.foldRight(emptyGraph)(addDependency(schema)) } -// println(s"Dependency graph: $r") + /*r match { + case Left(s) => println(s"Error calculating dependency graph: $s") + case Right(g) => + println(s"Dependency graph generated:\n${g.showEdges(_.toString)}\n---") + }*/ r } @@ -50,7 +54,7 @@ object Dependencies { deps.foldRight(graph)(combine) def combine(d: Dep, g: DepGraph[ShapeLabel]): DepGraph[ShapeLabel] = -// println(s"Adding edge $d to graph: $g") + // println(s"Adding edge $d to graph: $g") g.addEdge(d._1, d._2, d._3) def addDependency( @@ -60,13 +64,19 @@ object Dependencies { g <- graph label <- getLabel(se) deps <- dependencies(schema, se, label, Pos) + // _ <- { println(s"dependencies: ${deps}"); Right(()) } } yield addDependencies(g, deps) def getLabel(se: ShapeExpr): ES[ShapeLabel] = Either.fromOption(se.id, s"Shape $se has no label") - def dependencies(schema: Schema, shape: ShapeExpr, source: ShapeLabel, posNeg: PosNeg): ES[Deps] = - // println(s"Calculating dependencies of shape $shape with source label $source and posNeg $posNeg") + def dependencies( + schema: Schema, + shape: ShapeExpr, + source: ShapeLabel, + posNeg: PosNeg + ): ES[Deps] = + // println(s"Calculating dependencies of $source with shapeExpr $shape, posNeg $posNeg") shape match { case s: ShapeAnd => s.shapeExprs.map(dependencies(schema, _, source, posNeg)).sequence[ES, Deps].map(_.flatten) @@ -75,7 +85,7 @@ object Dependencies { s.shapeExprs.map(dependencies(schema, _, source, posNeg)).sequence[ES, Deps].map(_.flatten) case s: ShapeNot => - dependencies(schema, s.shapeExpr, source, Neg) + dependencies(schema, s.shapeExpr, source, posNeg.change) case _: NodeConstraint => noDeps @@ -108,7 +118,6 @@ object Dependencies { tripleExpr: TripleExpr, posNeg: PosNeg ): ES[Deps] = - // println(s"Calculating dependencies of tripleExpr $tripleExpr with source label $source and posNeg $posNeg") tripleExpr match { case t: EachOf => // TODO: Take into account max cardinality = 0 as a negative dependency? @@ -134,7 +143,7 @@ object Dependencies { case Some(ve) => if (tc.max == IntMax(0)) { // TODO: Should it be negative dependency? - dependencies(schema, ve, source, posNeg.change) + dependencies(schema, ve, source, posNeg) } else { dependencies(schema, ve, source, posNeg) } diff --git a/modules/shex/src/main/scala/es/weso/shex/ResolvedSchema.scala b/modules/shex/src/main/scala/es/weso/shex/ResolvedSchema.scala index e170ae34..922302c5 100644 --- a/modules/shex/src/main/scala/es/weso/shex/ResolvedSchema.scala +++ b/modules/shex/src/main/scala/es/weso/shex/ResolvedSchema.scala @@ -22,6 +22,7 @@ case class ResolvedSchema( resolvedMapShapeExprs: Map[ShapeLabel, ResolvedShapeExpr], resolvedMapTripleExprs: Map[ShapeLabel, ResolvedTripleExpr], inheritanceGraph: Inheritance[ShapeLabel, ShapesRelation], + // depGraph: DepGraph[ShapeLabel], labelLocationMap: Option[Map[ShapeLabel, Location]] ) extends AbstractSchema { diff --git a/modules/shex/src/main/scala/es/weso/shex/Schema.scala b/modules/shex/src/main/scala/es/weso/shex/Schema.scala index 9074f664..d3bd5590 100644 --- a/modules/shex/src/main/scala/es/weso/shex/Schema.scala +++ b/modules/shex/src/main/scala/es/weso/shex/Schema.scala @@ -101,13 +101,13 @@ case class Schema( def addTripleExprMap(te: Map[ShapeLabel, TripleExpr]): Schema = this.copy(optTripleExprMap = Some(te)) - def oddNegCycles: Either[String, Set[Set[(ShapeLabel, ShapeLabel)]]] = + lazy val oddNegCycles: Either[String, Set[Set[(ShapeLabel, ShapeLabel)]]] = Dependencies.oddNegCycles(this) - def negCycles: Either[String, Set[Set[(ShapeLabel, ShapeLabel)]]] = + lazy val negCycles: Either[String, Set[Set[(ShapeLabel, ShapeLabel)]]] = Dependencies.negCycles(this) - def depGraph: Either[String, DepGraph[ShapeLabel]] = + lazy val depGraph: Either[String, DepGraph[ShapeLabel]] = Dependencies.depGraph(this) def showCycles(str: Either[String, Set[Set[(ShapeLabel, ShapeLabel)]]]): String = str match { @@ -142,9 +142,9 @@ case class Schema( lazy val wellFormed: Either[String, Unit] = for { _ <- checkOddNegCycles - // _ <- { println(s"Passed checkOddNegCycles..."); Right(())} + _ <- { println(s"Passed checkOddNegCycles..."); Right(()) } _ <- checkBadShapeLabels - // _ <- { println(s"Passed checkBadShapeLabels..."); Right(())} + _ <- { println(s"Passed checkBadShapeLabels..."); Right(()) } } yield (()) def relativize(maybeBase: Option[IRI]): Schema = maybeBase match { @@ -161,7 +161,7 @@ case class Schema( def resolve(base: Option[IRI], verbose: VerboseLevel): IO[ResolvedSchema] = ResolvedSchema.resolve(this, base, verbose) - def withId(iri: IRI): Schema = this.copy(id = iri) + def withId(iri: IRI): Schema = this.copy(id = iri) def withShapes(ses: ShapeExpr*): Schema = this.copy(shapes = ses.toList.some) @@ -177,7 +177,6 @@ object Schema { def emptyWithId(iri: IRI): Schema = Schema.empty.withId(iri) - def fromIRI( i: IRI, base: Option[IRI], diff --git a/project/build.properties b/project/build.properties index fae470c0..4e2402af 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.8.0 +sbt.version=1.10.11 diff --git a/project/metals.sbt b/project/metals.sbt index aaf3382f..ce00deb3 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" % "2.0.9") // format: on diff --git a/project/plugins.sbt b/project/plugins.sbt index 7c1ad868..ee9e611d 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,13 +1,13 @@ -addSbtPlugin("com.codecommit" % "sbt-github-actions" % "0.14.2") -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0") +addSbtPlugin("com.github.sbt" % "sbt-github-actions" % "0.25.0") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.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.github.sbt" % "sbt-git" % "2.0.0") -addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.9.9") +addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.12") +addSbtPlugin("com.github.sbt" % "sbt-git" % "2.1.0") +addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.11.1") addSbtPlugin("org.lyranthe.sbt" % "partial-unification" % "1.1.2") addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.3.5") -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.0") +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.3.1") addSbtPlugin("com.simplytyped" % "sbt-antlr4" % "0.8.3") -addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.4.1") +addSbtPlugin("com.github.sbt" % "sbt-site-asciidoctor" % "1.5.0") addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1") diff --git a/project/project/metals.sbt b/project/project/metals.sbt index aaf3382f..ce00deb3 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" % "2.0.9") // format: on diff --git a/project/project/project/metals.sbt b/project/project/project/metals.sbt index aaf3382f..ce00deb3 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" % "2.0.9") // format: on diff --git a/src/main/scala/es/weso/shexs/Main.scala b/src/main/scala/es/weso/shexs/Main.scala index ef1f1d57..1318c3b7 100644 --- a/src/main/scala/es/weso/shexs/Main.scala +++ b/src/main/scala/es/weso/shexs/Main.scala @@ -10,6 +10,8 @@ import es.weso.shex.validator.Validator import es.weso.shextest.manifest.{Validate => _, _} import com.monovore.decline._ import com.monovore.decline.effect._ +import com.typesafe.scalalogging.LazyLogging + // import buildinfo._ import java.nio.file.Path import es.weso.shapepath.schemamappings.SchemaMappings @@ -45,7 +47,8 @@ object Main name = "shex-s", header = "ShEx-Scala command line tool", version = "0.2.2" // BuildInfo.version - ) { + ) + with LazyLogging { lazy val mappingOpt = Opts.option[Path]( "mapping", @@ -72,7 +75,31 @@ object Main if (verbose) IO.println(msg) else IO(()) - override def main: Opts[IO[ExitCode]] = + private def disable_logs(): Unit = { + // The following code is needed to remove extra logging from Jena + import org.apache.jena.riot.system.stream.JenaIOEnvironment + import org.apache.jena.riot.system.stream.LocationMapper + val mapper: LocationMapper = new LocationMapper() + JenaIOEnvironment.setGlobalLocationMapper(mapper) + + // Force logging level to None + val log: ch.qos.logback.classic.Logger = + logger.underlying.asInstanceOf[ch.qos.logback.classic.Logger] + log.getName() + import org.slf4j.LoggerFactory + import ch.qos.logback.classic._ + val es_weso_log: ch.qos.logback.classic.Logger = + LoggerFactory.getLogger("es.weso").asInstanceOf[ch.qos.logback.classic.Logger] + val org_log: ch.qos.logback.classic.Logger = + LoggerFactory.getLogger("org").asInstanceOf[ch.qos.logback.classic.Logger] + org_log.setLevel(Level.OFF) + es_weso_log.setLevel(Level.OFF) + log.setLevel(Level.OFF) + + } + + override def main: Opts[IO[ExitCode]] = { + disable_logs() schemaMappingCommand .orElse(Validate.validateCommand) .orElse(shapePathValidateCommand) @@ -90,6 +117,7 @@ object Main .map( _.handleErrorWith(infoError) ) + } def infoError(err: Throwable): IO[ExitCode] = IO.println(s"Error ${err.getLocalizedMessage()}") *> IO(ExitCode.Error) diff --git a/src/main/scala/es/weso/shexs/SchemaCommand.scala b/src/main/scala/es/weso/shexs/SchemaCommand.scala index 6b4fad18..2a066cdf 100644 --- a/src/main/scala/es/weso/shexs/SchemaCommand.scala +++ b/src/main/scala/es/weso/shexs/SchemaCommand.scala @@ -17,6 +17,7 @@ import io.circe._ import io.circe.syntax._ import es.weso.shex.Extends import es.weso.shex.References +import es.weso.shex.Schema sealed abstract class ShowMethod { val name: String @@ -53,6 +54,7 @@ object ShowMethod { case class SchemaCommand( schemaSpec: SchemaSpec, showInheritance: Boolean, + showDependencyGraph: Boolean, showMethod: ShowMethod, showShape: Option[ShapeLabel], verbose: VerboseLevel @@ -61,15 +63,29 @@ case class SchemaCommand( schema <- schemaSpec.getSchema(verbose) resolved <- ResolvedSchema.resolve(schema, schemaSpec.baseIRI, verbose) _ <- showShapeLabels(resolved) + _ <- showWellFormed(schema) _ <- if (showInheritance) runShowInheritance(resolved) else IO.pure(()) + _ <- + if (showDependencyGraph) showDepGraph(resolved) + else IO.pure(()) _ <- showShape match { case None => IO.pure(()) case Some(sl) => runShowShapeLabel(sl, resolved, showMethod) } } yield ExitCode.Success + private def showWellFormed(schema: Schema): IO[Unit] = { + val wellFormed = schema.wellFormed + wellFormed match { + case Left(msg) => + IO.println(s"Schema is NOT well-formed: ${msg}") + case Right(_) => + IO.println("Schema is well-formed") + } + } + private def showShapeLabels(schema: ResolvedSchema): IO[Unit] = { val labels = schema.resolvedMapShapeExprs.keySet IO.println( @@ -77,6 +93,16 @@ case class SchemaCommand( ) } + private def showDepGraph(schema: ResolvedSchema): IO[Unit] = { + val eitherDepGraph = schema.source.depGraph + eitherDepGraph match { + case Left(err) => + IO.println(s"Error obtaining dependency graph: $err") + case Right(depGraph) => + IO.println(s"Dependency graph:\n${depGraph.showEdges(lbl => schema.qualify(lbl.toRDFNode))}") + } + } + private def runShowInheritance(schema: ResolvedSchema): IO[Unit] = for { inheritanceStr <- schema.inheritanceGraph.show(lbl => schema.qualify(lbl.toRDFNode), r => s" -${r.name}-> ") @@ -118,7 +144,9 @@ object SchemaCommand { val showInheritance: Opts[Boolean] = Opts.flag("show-inheritance", short = "i", help = "show inheritance graph").orFalse -// val showMethod: Opts[ShowMethod] = Opts.option[String]("show-qualified", short = "q", help = "show shapes qualified by prefix declarations").orFalse + + val showDependencyGraph: Opts[Boolean] = + Opts.flag("show-dependency-graph", short = "d", help = "show dependency graph").orFalse val showShape: Opts[Option[ShapeLabel]] = UriOpt.uri("shape", help = "Show shape").map(uri => IRILabel(IRI(uri))).orNone @@ -128,6 +156,7 @@ object SchemaCommand { ( SchemaSpec.schemaSpec, showInheritance, + showDependencyGraph, ShowMethod.showMethodOpt, showShape, VerboseLevelOpt.verboseLevel diff --git a/version.sbt b/version.sbt index 007e6b01..c5cd8d93 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "0.2.33" +ThisBuild / version := "0.2.34"