Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add jsonld instance rendering by syntax, using terms names without lo… #1711

Merged
merged 1 commit into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package amf.shapes.client.platform

import amf.aml.client.platform.BaseAMLElementClient
import amf.core.client.platform.model.domain.DomainElement
import amf.core.internal.render.YNodeDocBuilderPopulator
import amf.shapes.client.platform.config.JsonLDSchemaConfiguration
import amf.shapes.client.scala.{JsonLDSchemaElementClient => InternalJsonLDSchemaElementClient}
import amf.shapes.internal.convert.ShapeClientConverters._
import org.yaml.builder.DocBuilder

import scala.scalajs.js.annotation.JSExportAll

@JSExportAll
class JsonLDSchemaElementClient private[amf] (private[amf] val _internal: InternalJsonLDSchemaElementClient)
extends BaseAMLElementClient(_internal) {

private[amf] def this(configuration: JsonLDSchemaConfiguration) = {
this(new InternalJsonLDSchemaElementClient(configuration))
}

override def getConfiguration(): JsonLDSchemaConfiguration = _internal.getConfiguration

override def renderToBuilder[T](element: DomainElement, builder: DocBuilder[T]): Unit = {
val node = _internal.renderElement(element, Nil)
YNodeDocBuilderPopulator.populate(node, builder)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package amf.shapes.client.platform.config

import amf.aml.client.platform.model.document.Dialect
import amf.core.client.platform.AMFGraphElementClient
import amf.core.client.platform.config.AMFEventListener
import amf.core.client.platform.errorhandling.ErrorHandlerProvider
import amf.core.client.platform.execution.ExecutionEnvironment
Expand All @@ -9,35 +10,41 @@ import amf.core.client.platform.resource.ResourceLoader
import amf.core.client.scala.transform._
import amf.core.client.platform.config._
import amf.core.internal.convert.CoreClientConverters.ClientFuture
import amf.shapes.client.platform.{BaseShapesConfiguration, ShapesConfiguration}
import amf.shapes.client.scala.config.{JsonLDSchemaConfiguration => InternalJsonLDSchemaDocumentConfiguration, JsonLDSchemaConfigurationClient => InternalJsonLDSchemaConfigurationClient}
import amf.shapes.client.platform.{BaseShapesConfiguration, JsonLDSchemaElementClient, ShapesConfiguration}
import amf.shapes.client.scala.config.{
JsonLDSchemaConfiguration => InternalJsonLDSchemaDocumentConfiguration,
JsonLDSchemaConfigurationClient => InternalJsonLDSchemaConfigurationClient
}
import amf.shapes.internal.convert.ShapeClientConverters._
import amf.core.internal.convert.ClientErrorHandlerConverter._



import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel}

@JSExportAll
class JsonLDSchemaConfiguration private [amf](
private [amf] override val _internal: InternalJsonLDSchemaDocumentConfiguration
class JsonLDSchemaConfiguration private[amf] (
private[amf] override val _internal: InternalJsonLDSchemaDocumentConfiguration
) extends BaseShapesConfiguration(_internal) {

/** Contains common AMF graph operations associated to documents */
override def baseUnitClient(): JsonLDSchemaConfigurationClient = _internal.baseUnitClient()

override def withParsingOptions(parsingOptions: ParsingOptions): JsonLDSchemaConfiguration = _internal.withParsingOptions(parsingOptions)
override def elementClient(): JsonLDSchemaElementClient = _internal.elementClient()

override def withParsingOptions(parsingOptions: ParsingOptions): JsonLDSchemaConfiguration =
_internal.withParsingOptions(parsingOptions)

override def withRenderOptions(renderOptions: RenderOptions): JsonLDSchemaConfiguration = _internal.withRenderOptions(renderOptions)
override def withRenderOptions(renderOptions: RenderOptions): JsonLDSchemaConfiguration =
_internal.withRenderOptions(renderOptions)

/** Add a [[ResourceLoader]]
* @param rl
* [[ResourceLoader]] to add to configuration object
* @return
* [[ShapesConfiguration]] with the [[ResourceLoader]] added
*/
/** Add a [[ResourceLoader]]
* @param rl
* [[ResourceLoader]] to add to configuration object
* @return
* [[ShapesConfiguration]] with the [[ResourceLoader]] added
*/

override def withResourceLoader(rl: ResourceLoader): JsonLDSchemaConfiguration = _internal.withResourceLoader(ResourceLoaderMatcher.asInternal(rl))
override def withResourceLoader(rl: ResourceLoader): JsonLDSchemaConfiguration =
_internal.withResourceLoader(ResourceLoaderMatcher.asInternal(rl))

/** Set the configuration [[ResourceLoader]]s
*
Expand All @@ -47,23 +54,29 @@ class JsonLDSchemaConfiguration private [amf](
* [[ShapesConfiguration]] with [[ResourceLoader]]s set
*/

override def withResourceLoaders(rl: ClientList[ResourceLoader]): JsonLDSchemaConfiguration = _internal.withResourceLoaders(rl.asInternal.toList)
override def withResourceLoaders(rl: ClientList[ResourceLoader]): JsonLDSchemaConfiguration =
_internal.withResourceLoaders(rl.asInternal.toList)

override def withUnitCache(cache: UnitCache): JsonLDSchemaConfiguration = _internal.withUnitCache(UnitCacheMatcher.asInternal(cache))
override def withUnitCache(cache: UnitCache): JsonLDSchemaConfiguration =
_internal.withUnitCache(UnitCacheMatcher.asInternal(cache))

def withTransformationPipeline(pipeline: TransformationPipeline): JsonLDSchemaConfiguration = _internal.withTransformationPipeline(pipeline)
def withTransformationPipeline(pipeline: TransformationPipeline): JsonLDSchemaConfiguration =
_internal.withTransformationPipeline(pipeline)

override def withErrorHandlerProvider(provider: ErrorHandlerProvider): JsonLDSchemaConfiguration = _internal.withErrorHandlerProvider(() => provider.errorHandler())
override def withErrorHandlerProvider(provider: ErrorHandlerProvider): JsonLDSchemaConfiguration =
_internal.withErrorHandlerProvider(() => provider.errorHandler())

override def withEventListener(listener: AMFEventListener): JsonLDSchemaConfiguration = _internal.withEventListener(listener)
override def withEventListener(listener: AMFEventListener): JsonLDSchemaConfiguration =
_internal.withEventListener(listener)

def withExecutionEnvironment(executionEnv: ExecutionEnvironment): JsonLDSchemaConfiguration = _internal.withExecutionEnvironment(executionEnv._internal)
def withExecutionEnvironment(executionEnv: ExecutionEnvironment): JsonLDSchemaConfiguration =
_internal.withExecutionEnvironment(executionEnv._internal)

override def withDialect(dialect: Dialect): JsonLDSchemaConfiguration = _internal.withDialect(dialect)

def withDialect(url: String): ClientFuture[JsonLDSchemaConfiguration] = _internal.withDialect(url).asClient

def forInstance(url:String): ClientFuture[JsonLDSchemaConfiguration] = _internal.forInstance(url).asClient
def forInstance(url: String): ClientFuture[JsonLDSchemaConfiguration] = _internal.forInstance(url).asClient

}
@JSExportAll
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package amf.shapes.client.scala

import amf.core.client.scala.model.document.BaseUnit
import amf.core.client.scala.model.domain.DomainElement
import amf.core.internal.render.BaseEmitters.traverse
import amf.shapes.client.scala.config.JsonLDSchemaConfiguration
import amf.shapes.client.scala.model.domain.jsonldinstance.JsonLDObject
import amf.shapes.client.scala.render.{JsonLDObjectRender, TermNameSyntaxProvider}
import org.yaml.builder.YDocumentBuilder
import org.yaml.model.{YDocument, YNode}

class JsonLDSchemaElementClient private[amf] (override protected val configuration: JsonLDSchemaConfiguration)
extends ShapesElementClient(configuration) {
override def renderElement(element: DomainElement, references: Seq[BaseUnit]): YNode = {
element match {
case jsonLdObject: JsonLDObject =>
val emitter = new JsonLDObjectRender(jsonLdObject, TermNameSyntaxProvider)
val document = YDocument { b =>
traverse(Seq(emitter), b)
}
document.node
case _ => super.renderElement(element, references)
}
}

override def getConfiguration: JsonLDSchemaConfiguration = configuration
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import amf.core.internal.registries.AMFRegistry
import amf.core.internal.resource.AMFResolvers
import amf.core.internal.validation.EffectiveValidations
import amf.core.internal.validation.core.ValidationProfile
import amf.shapes.client.scala.ShapesConfiguration
import amf.shapes.client.scala.{JsonLDSchemaElementClient, ShapesConfiguration, ShapesElementClient}
import amf.shapes.client.scala.model.document.JsonSchemaDocument
import amf.shapes.internal.convert.JsonLDSchemaRegister
import amf.shapes.internal.plugins.render.AMFJsonLDSchemaGraphRenderPlugin
Expand Down Expand Up @@ -53,6 +53,7 @@ class JsonLDSchemaConfiguration private[amf] (
)
override def baseUnitClient(): JsonLDSchemaConfigurationClient = new JsonLDSchemaConfigurationClient(this)

override def elementClient(): JsonLDSchemaElementClient = new JsonLDSchemaElementClient(this)
def withJsonLDSchema(jsonDocument: JsonSchemaDocument): JsonLDSchemaConfiguration = {
val transformed = if (!jsonDocument.processingData.transformed.value()) transform(jsonDocument) else jsonDocument

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ case class JsonLDObject(

private def buildArray(values: Seq[JsonLDElement]) = JsonLDArray(values)

private def updateModel(field: Field) = model.copy(fields = model.fields.filterNot(_ == field) :+ field)
private def updateModel(field: Field) = {
if (model.fields.contains(field)) model // preserve initial order
else model.copy(fields = model.fields :+ field)
}
private def copyWithProperty(field: Field, element: JsonLDElement) =
copy(fields = fields.copy(), model = updateModel(field)).set(field, element)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package amf.shapes.client.scala.render

import amf.core.client.platform.model.DataTypes
import amf.core.client.scala.model.domain.{AmfArray, AmfElement, AmfScalar}
import amf.core.client.scala.vocabulary.{Namespace, ValueType}
import amf.core.internal.metamodel.{Obj, Type}
import amf.core.internal.metamodel.Type.{ArrayLike, Scalar}
import amf.core.internal.parser.domain.Value
import amf.core.internal.render.emitters.PartEmitter
import amf.shapes.client.scala.model.domain.jsonldinstance.JsonLDObject
import org.mulesoft.common.client.lexical.Position
import org.yaml.model.{YDocument, YNode}
import org.yaml.model.YDocument.{EntryBuilder, PartBuilder}

class JsonLDObjectRender(obj: JsonLDObject, syntaxProvider: SyntaxProvider) extends PartEmitter {
override def emit(b: YDocument.PartBuilder): Unit = {
emitObject(obj, b)
}

private def emitElement(element: AmfElement, pb: PartBuilder): Unit = element match {
case scalar: AmfScalar => emitScalar(scalar, pb)
case arr: AmfArray => emitArray(arr, pb)
case obj: JsonLDObject => emitObject(obj, pb)
case _ => ???
}

private def emitObject(innerObj: JsonLDObject, builder: YDocument.PartBuilder): Unit = {
builder.obj(eb => {
innerObj.meta.fields.filter(f => innerObj.fields.exists(f)).foreach { field =>
val element: AmfElement = innerObj.fields.get(field)
val pbFunc: PartBuilder => Unit = (pb: PartBuilder) => {
emitElement(element, pb)
}
eb.entry(syntaxProvider.keyFor(obj.meta.typeIris.head, field.value.iri()), pbFunc)
}
})
}

private def emitArray(arr: AmfArray, pb: PartBuilder) = {
pb.list(f => arr.values.foreach(emitElement(_, f)))
}

private def emitScalar(scalar: AmfScalar, pb: PartBuilder): Unit = {
scalar.value match {
case s: String => pb += s
case i: Int => pb += i
case f: Float => pb += f
case b: Boolean => pb += b
case _ => pb += YNode.Null
}
}

override def position(): Position = Position.ZERO
}

trait SyntaxProvider {

def keyFor(clazz: String, property: String): String
}

object TermNameSyntaxProvider extends SyntaxProvider {
override def keyFor(clazz: String, property: String): String = ValueType(property).name
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,33 @@ package amf.shapes.internal.convert
import amf.aml.internal.convert.VocabulariesBaseConverter
import amf.core.internal.convert.BidirectionalMatcher
import amf.core.internal.unsafe.PlatformSecrets
import amf.shapes.client.platform.config.{JsonLDSchemaConfiguration, JsonLDSchemaConfigurationClient, AMFSemanticSchemaResult => ClientAMFSemanticSchemaResult, SemanticJsonSchemaConfiguration => ClientSemanticJsonSchemaConfiguration}
import amf.shapes.client.platform.config.{
JsonLDSchemaConfiguration,
JsonLDSchemaConfigurationClient,
AMFSemanticSchemaResult => ClientAMFSemanticSchemaResult,
SemanticJsonSchemaConfiguration => ClientSemanticJsonSchemaConfiguration
}
import amf.shapes.client.platform.model.document.{JsonSchemaDocument => ClientJsonSchemaDocument}
import amf.shapes.client.scala.model.document.JsonSchemaDocument
import amf.shapes.client.platform.model.domain
import amf.shapes.client.platform.{JsonLDInstanceResult, JsonLDSchemaResult, ShapesConfiguration => ClientShapesConfiguration}
import amf.shapes.client.platform.{
JsonLDInstanceResult,
JsonLDSchemaElementClient,
JsonLDSchemaResult,
ShapesConfiguration => ClientShapesConfiguration
}
import amf.shapes.client.scala.ShapesConfiguration
import amf.shapes.client.scala.config.{AMFSemanticSchemaResult, SemanticJsonSchemaConfiguration, JsonLDSchemaConfiguration => InternalJsonLDSchemaConfiguration, JsonLDSchemaConfigurationClient => InternalJsonLDSchemaConfigurationClient}
import amf.shapes.client.scala.model.domain._
import amf.shapes.client.scala.model.domain.federation._
import amf.shapes.client.platform.model.domain.jsonldinstance.{JsonLDArray, JsonLDElement, JsonLDObject, JsonLDScalar}
import amf.shapes.client.scala.model.domain.jsonldinstance
import amf.shapes.client.scala.model.domain.operations._
import amf.shapes.client.scala.{JsonLDInstanceResult => InternalJsonLDInstanceResult, JsonLDSchemaResult => InternalJsonLDSchemaResult}
import amf.shapes.client.scala.{
JsonLDSchemaElementClient => InternalJsonLDSchemaElementClient,
JsonLDInstanceResult => InternalJsonLDInstanceResult,
JsonLDSchemaResult => InternalJsonLDSchemaResult
}

trait ShapesBaseConverter
extends VocabulariesBaseConverter
Expand Down Expand Up @@ -214,7 +228,6 @@ trait SemanticSchemaConfigurationConverter {
}
}


trait AMFSemanticSchemaResultConverter {
implicit object AMFSemanticSchemaResultMatcher
extends BidirectionalMatcher[AMFSemanticSchemaResult, ClientAMFSemanticSchemaResult] {
Expand Down Expand Up @@ -377,16 +390,18 @@ trait JsonLDElementConverter extends PlatformSecrets {

}

trait JsonLDSchemaResultConverter extends PlatformSecrets{
implicit object JsonLDSchemaResultConverter extends BidirectionalMatcher[InternalJsonLDSchemaResult, JsonLDSchemaResult]{
trait JsonLDSchemaResultConverter extends PlatformSecrets {
implicit object JsonLDSchemaResultConverter
extends BidirectionalMatcher[InternalJsonLDSchemaResult, JsonLDSchemaResult] {
override def asInternal(from: JsonLDSchemaResult): InternalJsonLDSchemaResult = from._internal

override def asClient(from: InternalJsonLDSchemaResult): JsonLDSchemaResult = new JsonLDSchemaResult(from)
}
}

trait JsonLDInstanceResultConverter extends PlatformSecrets{
implicit object JsonLDInstanceResultConverter extends BidirectionalMatcher[InternalJsonLDInstanceResult, JsonLDInstanceResult]{
trait JsonLDInstanceResultConverter extends PlatformSecrets {
implicit object JsonLDInstanceResultConverter
extends BidirectionalMatcher[InternalJsonLDInstanceResult, JsonLDInstanceResult] {
override def asInternal(from: JsonLDInstanceResult): InternalJsonLDInstanceResult = from._internal

override def asClient(from: InternalJsonLDInstanceResult): JsonLDInstanceResult = new JsonLDInstanceResult(from)
Expand All @@ -397,7 +412,16 @@ trait JsonLDSchemaConfigurationConverter extends PlatformSecrets{
implicit object JsonLDSchemaConfigurationConverter extends BidirectionalMatcher[InternalJsonLDSchemaConfiguration, JsonLDSchemaConfiguration]{
override def asInternal(from: JsonLDSchemaConfiguration): InternalJsonLDSchemaConfiguration = from._internal

override def asClient(from: InternalJsonLDSchemaConfiguration): JsonLDSchemaConfiguration = new JsonLDSchemaConfiguration(from)
override def asClient(from: InternalJsonLDSchemaConfiguration): JsonLDSchemaConfiguration =
new JsonLDSchemaConfiguration(from)
}

implicit object JsonLDSchemaElementClientConverter
extends BidirectionalMatcher[InternalJsonLDSchemaElementClient, JsonLDSchemaElementClient] {
override def asInternal(from: JsonLDSchemaElementClient): InternalJsonLDSchemaElementClient = from._internal

override def asClient(from: InternalJsonLDSchemaElementClient): JsonLDSchemaElementClient =
new JsonLDSchemaElementClient(from)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package amf.shapes.client.jsonldschema.render

import amf.core.client.scala.vocabulary.ValueType
import amf.core.internal.metamodel.domain.common.DescribedElementModel
import amf.shapes.client.scala.config.JsonLDSchemaConfiguration
import amf.shapes.client.scala.model.domain.jsonldinstance.JsonLDObject
import amf.shapes.internal.domain.metamodel.jsonldschema.JsonLDEntityModel
import amf.shapes.internal.spec.jsonldschema.parser.JsonPath
import org.scalatest.funsuite.AsyncFunSuite
import org.scalatest.matchers.should.Matchers
import org.yaml.render.YamlRender

class JsonLDObjectRenderTest extends AsyncFunSuite with Matchers {

val base = "http://a.ml/jsonld#"

val model =
JsonLDEntityModel(List(ValueType(s"${base}Object")), List(DescribedElementModel.Description), JsonPath.empty)

val innerObjKey = s"${base}keyObj"
val rootKey = base + "key"

val model2 =
JsonLDEntityModel(List(ValueType(s"${base}Object2")), List(DescribedElementModel.Description), JsonPath.empty)
val obj = JsonLDObject
.empty(model, JsonPath.empty)
.withProperty(rootKey, "value")
.withProperty(innerObjKey, JsonLDObject.empty(model, JsonPath.empty).withProperty(s"${base}innerObj", "ab"))

val expected =
"""key: value
|keyObj:
| innerObj: ab""".stripMargin
test("serialize jsonldObject") {
val node = JsonLDSchemaConfiguration.JsonLDSchema().elementClient().renderElement(obj, Nil)
val result = YamlRender.render(node)
result shouldBe (expected)
}

test("serialize mutated inner jsonldObject") {
val innerObj = obj.graph.getObjectByProperty(innerObjKey).collectFirst({ case obj: JsonLDObject => obj }).head
obj.withProperty(innerObjKey, innerObj.withProperty(s"${base}innerObjKey2", 2)).withProperty(rootKey, "value2")

val node = JsonLDSchemaConfiguration.JsonLDSchema().elementClient().renderElement(obj, Nil)
val result = YamlRender.render(node)
result shouldBe (expected)
}
}