diff --git a/.gitignore b/.gitignore index e3f031f..31b7cc5 100644 --- a/.gitignore +++ b/.gitignore @@ -95,4 +95,6 @@ project/plugins/project/ .lib/ # Ignore Gradle build output directory build -.bsp \ No newline at end of file +.bsp +.metals +.vscode diff --git a/exporters/src/main/scala/amf/exporters/CanonicalWebAPISpecDialectExporter.scala b/exporters/src/main/scala/amf/exporters/CanonicalWebAPISpecDialectExporter.scala index f4fdbe3..7773c43 100644 --- a/exporters/src/main/scala/amf/exporters/CanonicalWebAPISpecDialectExporter.scala +++ b/exporters/src/main/scala/amf/exporters/CanonicalWebAPISpecDialectExporter.scala @@ -6,7 +6,14 @@ import java.io.{File, FileWriter, StringWriter, Writer} import amf.core.internal.metamodel.Type.Scalar import amf.core.internal.metamodel.document.BaseUnitModel import amf.core.internal.metamodel.{Field, Obj, Type} -import amf.core.internal.metamodel.domain.{DataNodeModel, DomainElementModel, LinkableElementModel, ModelDoc, ModelVocabularies, ObjectNodeModel} +import amf.core.internal.metamodel.domain.{ + DataNodeModel, + DomainElementModel, + LinkableElementModel, + ModelDoc, + ModelVocabularies, + ObjectNodeModel +} import org.reflections.Reflections import org.reflections.scanners.SubTypesScanner import org.yaml.model.YPart @@ -200,10 +207,6 @@ class CanonicalWebAPISpecDialectExporter(logger: Logger = ConsoleLogger) { DomainElementModel.CustomDomainProperties.value.iri(), BaseUnitModel.ProcessingData.value.iri(), BaseUnitModel.SourceInformation.value.iri(), - - // graphQL model that is still not definitive - NodeShapeModel.Operations.value.iri(), - NodeShapeModel.IsAbstract.value.iri() ) val blocklistedSupertypes: Set[String] = Set( @@ -226,14 +229,6 @@ class CanonicalWebAPISpecDialectExporter(logger: Logger = ConsoleLogger) { (Namespace.Document + "BaseUnitProcessingData").iri(), (Namespace.Document + "BaseUnitSourceInformation").iri(), (Namespace.Document + "LocationInformation").iri(), - - // graphQL model that is still not definitive - (Namespace.Shapes + "Operation").iri(), - (Namespace.Shapes + "Parameter").iri(), - (Namespace.Shapes + "Payload").iri(), - (Namespace.Shapes + "Request").iri(), - (Namespace.Shapes + "Response").iri(), - ) val shapeUnionDeclaration = "DataShapesUnion" @@ -359,6 +354,9 @@ class CanonicalWebAPISpecDialectExporter(logger: Logger = ConsoleLogger) { | allowMultiple: true """.stripMargin + val requestExtends: String = messageExtends + val responseExtends: String = messageExtends + val dataNodeUnionDeclaration = "DataNodeUnion" val dataNodeUnion: String = s""" @@ -477,7 +475,7 @@ class CanonicalWebAPISpecDialectExporter(logger: Logger = ConsoleLogger) { val channelBindingUnionDeclaration: String = "ChannelBindingUnion" val channelBindingUnion: String = - s""" $channelBindingUnionDeclaration: + s""" $channelBindingUnionDeclaration: | typeDiscriminatorName: bindingType | typeDiscriminator: | WebSockets: WebSocketsChannelBinding @@ -619,6 +617,10 @@ class CanonicalWebAPISpecDialectExporter(logger: Logger = ConsoleLogger) { stringBuilder.append(operationExtends + "\n") } else if (dialectNodeMapping.classTerm == (Namespace.ApiContract + "Message").iri()) { stringBuilder.append(messageExtends + "\n") + } else if (dialectNodeMapping.classTerm == (Namespace.ApiContract + "Request").iri()) { + stringBuilder.append(requestExtends + "\n") + } else if (dialectNodeMapping.classTerm == (Namespace.ApiContract + "Response").iri()) { + stringBuilder.append(responseExtends + "\n") } else if (dialectNodeMapping.classTerm == (Namespace.Document + "Unit").iri()) { stringBuilder.append(baseUnitLocation) } @@ -681,7 +683,8 @@ class CanonicalWebAPISpecDialectExporter(logger: Logger = ConsoleLogger) { stringBuilder.append(s" range: link\n") } - val annotationMapping = dialectNodeMapping.propertyMappings.find(_.propertyTerm == DomainElementModel.CustomDomainProperties.value.iri()) + val annotationMapping = dialectNodeMapping.propertyMappings.find( + _.propertyTerm == DomainElementModel.CustomDomainProperties.value.iri()) if (annotationMapping.isDefined) { stringBuilder.append(s" designAnnotations:\n") val (compacted, _, _) = compact(DesignAnnotationField.value.iri()) @@ -761,15 +764,14 @@ class CanonicalWebAPISpecDialectExporter(logger: Logger = ConsoleLogger) { } } - object CanonicalWebAPISpecDialectExporter { val DIALECT_FILE = "vocabulary/src/main/resources/dialects/canonical_webapi_spec.yaml" def main(args: Array[String]): Unit = { val exporter = new CanonicalWebAPISpecDialectExporter() - val f = new File(DIALECT_FILE) - val writer = new FileWriter(f) + val f = new File(DIALECT_FILE) + val writer = new FileWriter(f) exporter.dumpDialect(writer) } } diff --git a/exporters/src/main/scala/amf/exporters/VocabularyExporter.scala b/exporters/src/main/scala/amf/exporters/VocabularyExporter.scala index 93cf6ef..f7730e7 100644 --- a/exporters/src/main/scala/amf/exporters/VocabularyExporter.scala +++ b/exporters/src/main/scala/amf/exporters/VocabularyExporter.scala @@ -1,26 +1,25 @@ package amf.exporters -import amf.apicontract.client.platform.model.document.APIContractProcessingData import amf.apicontract.internal.metamodel.document.APIContractProcessingDataModel import amf.core.client.scala.vocabulary.Namespace - -import java.io.{File, FileWriter, Writer} import amf.core.internal.metamodel.Type.{Bool, Date, DateTime, Double, EncodedIri, Float, Int, Iri, RegExp, Str, Time} -import amf.core.internal.metamodel.document.{BaseUnitModel, BaseUnitProcessingDataModel, BaseUnitSourceInformationModel, LocationInformationModel} +import amf.core.internal.metamodel.document.{ + BaseUnitModel, + BaseUnitProcessingDataModel, + BaseUnitSourceInformationModel, + LocationInformationModel +} import amf.core.internal.metamodel.domain._ import amf.core.internal.metamodel.{Field, Obj, Type} import amf.shapes.internal.domain.metamodel.NodeShapeModel import amf.shapes.internal.domain.metamodel.operations.ShapeOperationModel -import amf.transform.internal.canonical.CanonicalWebAPISpecExtraModel import amf.transform.internal.canonical.CanonicalWebAPISpecExtraModel._ import org.reflections.Reflections import org.reflections.scanners.SubTypesScanner import org.yaml.model.YDocument import org.yaml.render.YamlRender -import scala.annotation.tailrec -import scala.collection.mutable -import scala.collection.mutable.ArrayBuffer +import java.io.{File, FileWriter} import scala.annotation.tailrec import scala.collection.mutable import scala.collection.mutable.ArrayBuffer @@ -67,17 +66,13 @@ object VocabularyExporter { val dependencies: mutable.Map[String, ArrayBuffer[ModelVocabulary]] = mutable.Map[String, mutable.ArrayBuffer[ModelVocabulary]]() - val externalVocabularyClasses - : mutable.Map[String, ArrayBuffer[VocabClassTerm]] = - ExternalModelVocabularies.all.foldLeft( - mutable.Map[String, mutable.ArrayBuffer[VocabClassTerm]]()) { + val externalVocabularyClasses: mutable.Map[String, ArrayBuffer[VocabClassTerm]] = + ExternalModelVocabularies.all.foldLeft(mutable.Map[String, mutable.ArrayBuffer[VocabClassTerm]]()) { case (acc, externalVocab) => acc + (externalVocab.alias -> mutable.ArrayBuffer[VocabClassTerm]()) } - val externalVocabularyProperties - : mutable.Map[String, ArrayBuffer[VocabPropertyTerm]] = - ExternalModelVocabularies.all.foldLeft( - mutable.Map[String, mutable.ArrayBuffer[VocabPropertyTerm]]()) { + val externalVocabularyProperties: mutable.Map[String, ArrayBuffer[VocabPropertyTerm]] = + ExternalModelVocabularies.all.foldLeft(mutable.Map[String, mutable.ArrayBuffer[VocabPropertyTerm]]()) { case (acc, externalVocab) => acc + (externalVocab.alias -> mutable.ArrayBuffer[VocabPropertyTerm]()) } @@ -120,13 +115,6 @@ object VocabularyExporter { (Namespace.Document + "BaseUnitProcessingData").iri(), (Namespace.Document + "BaseUnitSourceInformation").iri(), (Namespace.Document + "LocationInformation").iri(), - - // graphQL model that is still not definitive - (Namespace.Shapes + "Operation").iri(), - (Namespace.Shapes + "Parameter").iri(), - (Namespace.Shapes + "Payload").iri(), - (Namespace.Shapes + "Request").iri(), - (Namespace.Shapes + "Response").iri(), ) val blockedProperties: Seq[String] = Seq( @@ -138,57 +126,41 @@ object VocabularyExporter { BaseUnitSourceInformationModel.AdditionalLocations.value.iri(), BaseUnitSourceInformationModel.RootLocation.value.iri(), LocationInformationModel.Elements.value.iri(), - - // graphQL model that is still not definitive - NodeShapeModel.Operations.value.iri(), - NodeShapeModel.IsAbstract.value.iri(), - ShapeOperationModel.Request.value.iri(), - ShapeOperationModel.Response.value.iri(), ) val blocklist: Map[ModelVocabulary, Seq[ModelVocabulary]] = Map() - val reflectionsExtensions = new Reflections( - "amf.core.internal.metamodel.domain.extensions", - new SubTypesScanner(false)) + val reflectionsExtensions = + new Reflections("amf.core.internal.metamodel.domain.extensions", new SubTypesScanner(false)) val reflectionsCoreDoc = new Reflections("amf.core.internal.metamodel.document", new SubTypesScanner(false)) val reflectionsCoreDomain = new Reflections("amf.core.internal.metamodel.domain", new SubTypesScanner(false)) - val reflectionsWebApi = new Reflections("amf.apicontract.internal.metamodel.domain", - new SubTypesScanner(false)) - val reflectionsWebApiDoc = new Reflections( - "amf.apicontract.internal.metamodel.document", - new SubTypesScanner(false)) + val reflectionsWebApi = new Reflections("amf.apicontract.internal.metamodel.domain", new SubTypesScanner(false)) + val reflectionsWebApiDoc = new Reflections("amf.apicontract.internal.metamodel.document", new SubTypesScanner(false)) val reflectionsTemplates = - new Reflections("amf.core.internal.metamodel.domain.templates", - new SubTypesScanner(false)) - val reflectionsShapes = new Reflections("amf.shapes.internal.domain.metamodel", - new SubTypesScanner(false)) + new Reflections("amf.core.internal.metamodel.domain.templates", new SubTypesScanner(false)) + val reflectionsShapes = new Reflections("amf.shapes.internal.domain.metamodel", new SubTypesScanner(false)) val reflectionsVocabularies = - new Reflections("amf.aml.internal.metamodel.domain", - new SubTypesScanner(false)) + new Reflections("amf.aml.internal.metamodel.domain", new SubTypesScanner(false)) val reflectionsVocabDoc = - new Reflections("amf.aml.internal.metamodel.document", - new SubTypesScanner(false)) + new Reflections("amf.aml.internal.metamodel.document", new SubTypesScanner(false)) val reflectionsExtModel = new Reflections("amf.transform", new SubTypesScanner(false)) - var files: Map[String, VocabularyFile] = Map() - var classToFile: Map[String, String] = Map() - var classes: Map[String, VocabClassTerm] = Map() + var files: Map[String, VocabularyFile] = Map() + var classToFile: Map[String, String] = Map() + var classes: Map[String, VocabClassTerm] = Map() var properties: Map[String, VocabPropertyTerm] = Map() def fillInitialFiles(): Unit = { ModelVocabularies.all.foreach { vocab: ModelVocabulary => - files = files + (vocab.filename -> VocabularyFile(base = vocab.base, - usage = vocab.usage)) + files = files + (vocab.filename -> VocabularyFile(base = vocab.base, usage = vocab.usage)) } } val emitProperties = false - def notBlocklisted(klasses: Seq[String], - vocabulary: ModelVocabulary): Seq[String] = { + def notBlocklisted(klasses: Seq[String], vocabulary: ModelVocabulary): Seq[String] = { val vocabBlocklist: Seq[ModelVocabulary] = blocklist.getOrElse(vocabulary, Seq()) val res = klasses.filter { klassName => @@ -203,16 +175,15 @@ object VocabularyExporter { res } - val ShaclShape: String = (Namespace.Shacl + "Shape").iri() + val ShaclShape: String = (Namespace.Shacl + "Shape").iri() val ShapesShape: String = (Namespace.Shapes + "Shape").iri() - val AnyShape: String = (Namespace.Shapes + "AnyShape").iri() + val AnyShape: String = (Namespace.Shapes + "AnyShape").iri() def blocklistedSuperClass(klass: String, superClass: String): Boolean = { (klass, superClass) match { case (ShapesShape, ShaclShape) => false case (AnyShape, ShapesShape) => false case (AnyShape, ShaclShape) => true - case (base, ShaclShape) - if base.startsWith(ModelVocabularies.Shapes.base) => + case (base, ShaclShape) if base.startsWith(ModelVocabularies.Shapes.base) => true case (_, ShapesShape) => true case _ => false @@ -220,9 +191,9 @@ object VocabularyExporter { } private def renderVocabulary(vocabulary: ModelVocabulary): String = { - val vocabClasses = classesForVocabulary(vocabulary) + val vocabClasses = classesForVocabulary(vocabulary) val vocabProperties = propertiesForVocabulary(vocabulary) - val uses = usesReferences(vocabulary, vocabClasses, vocabProperties) + val uses = usesReferences(vocabulary, vocabClasses, vocabProperties) val document = YDocument(b => { b.comment("%Vocabulary 1.0") @@ -273,30 +244,23 @@ object VocabularyExporter { b.obj { b => if (classTerm.displayName != null && classTerm.displayName != "") { - b.entry("displayName", - classTerm.displayName) + b.entry("displayName", classTerm.displayName) } else { - b.entry("displayName", - uriAlias(classTerm.id)) + b.entry("displayName", uriAlias(classTerm.id)) } if (classTerm.description != "") { - b.entry("description", - classTerm.description) + b.entry("description", classTerm.description) } else if (externalDescription .get(classTerm.id) .isDefined) { - b.entry("description", - externalDescription(classTerm.id)) + b.entry("description", externalDescription(classTerm.id)) } val superClasses = - notBlocklisted(classTerm.superClasses, - vocabulary).filter(sk => + notBlocklisted(classTerm.superClasses, vocabulary).filter(sk => !blocklistedSuperClass(classTerm.id, sk)) if (superClasses.nonEmpty) { if (superClasses.length == 1) { - b.entry("extends", - compactUri(superClasses.head, - vocabulary)) + b.entry("extends", compactUri(superClasses.head, vocabulary)) } else { b.entry("extends", b => { b.list { l => @@ -332,37 +296,27 @@ object VocabularyExporter { b.obj { b => if (propertyTerm.displayName != null && propertyTerm.displayName != "") { - b.entry("displayName", - propertyTerm.displayName) + b.entry("displayName", propertyTerm.displayName) } else { - b.entry("displayName", - uriAlias(propertyTerm.id)) + b.entry("displayName", uriAlias(propertyTerm.id)) } if (propertyTerm.description != "") { - b.entry("description", - propertyTerm.description) + b.entry("description", propertyTerm.description) } else if (externalDescription .get(propertyTerm.id) .isDefined) { - b.entry( - "description", - externalDescription(propertyTerm.id)) + b.entry("description", externalDescription(propertyTerm.id)) } val superProperties = - notBlocklisted(propertyTerm.superClasses, - vocabulary) + notBlocklisted(propertyTerm.superClasses, vocabulary) if (superProperties.nonEmpty) { if (propertyTerm.superClasses.length == 1) { - b.entry("extends", - compactUri( - propertyTerm.superClasses.head, - vocabulary)) + b.entry("extends", compactUri(propertyTerm.superClasses.head, vocabulary)) } else { b.entry("extends", b => { b.list { l => - propertyTerm.superClasses.foreach { - t => - l += compactUri(t, vocabulary) + propertyTerm.superClasses.foreach { t => + l += compactUri(t, vocabulary) } } }) @@ -370,17 +324,11 @@ object VocabularyExporter { } if (propertyTerm.scalarRange.nonEmpty) { - b.entry("range", - propertyTerm.scalarRange.get) + b.entry("range", propertyTerm.scalarRange.get) } if (propertyTerm.objectRange.nonEmpty) { - if (notBlocklisted( - Seq(propertyTerm.objectRange.get), - vocabulary).nonEmpty) { - b.entry( - "range", - compactUri(propertyTerm.objectRange.get, - vocabulary)) + if (notBlocklisted(Seq(propertyTerm.objectRange.get), vocabulary).nonEmpty) { + b.entry("range", compactUri(propertyTerm.objectRange.get, vocabulary)) } } } @@ -420,8 +368,7 @@ object VocabularyExporter { } } - def propertiesForVocabulary( - vocabulary: ModelVocabulary): Seq[VocabPropertyTerm] = { + def propertiesForVocabulary(vocabulary: ModelVocabulary): Seq[VocabPropertyTerm] = { // Properties declared as belonging to this vocabulary val explicitProperties: Seq[VocabPropertyTerm] = allProperties @@ -480,16 +427,14 @@ object VocabularyExporter { // Classes in this vocabulary because they are used in extension from other classes val implicitClassesExtension: Seq[String] = allClasses.flatMap { klass => klass.superClasses.filter { superClass => - superClass.startsWith(vocabulary.base) && !explicitClassesMap.contains( - superClass) + superClass.startsWith(vocabulary.base) && !explicitClassesMap.contains(superClass) } } // Implicit IDs -> simple class terms val implicitClasses = - (implicitClassesExtension ++ implicitClassesExtension).distinct.map { - klassId => - VocabClassTerm(klassId, uriAlias(klassId), "", Seq(), Seq()) + (implicitClassesExtension ++ implicitClassesExtension).distinct.map { klassId => + VocabClassTerm(klassId, uriAlias(klassId), "", Seq(), Seq()) } // final set of classes @@ -497,10 +442,9 @@ object VocabularyExporter { classes.filter(vocab => !blockedClasses.contains(vocab.id)) } - def usesReferences( - vocabulary: ModelVocabulary, - classTerms: Seq[VocabClassTerm], - propertyTerms: Seq[VocabPropertyTerm]): Seq[ModelVocabulary] = { + def usesReferences(vocabulary: ModelVocabulary, + classTerms: Seq[VocabClassTerm], + propertyTerms: Seq[VocabPropertyTerm]): Seq[ModelVocabulary] = { val classExtendsRefs = classTerms.flatMap { klass => klass.superClasses.filter(!_.startsWith(vocabulary.base)) } @@ -514,13 +458,12 @@ object VocabularyExporter { } val vocabularies = - (classExtendsRefs ++ propertiesExtendsRefs ++ propertiesRangeRefs).map { - id => - findNamespace(id) match { - case Some(vocab) => vocab - case None => - throw new Exception(s"Cannot find vocabulary for URI term $id") - } + (classExtendsRefs ++ propertiesExtendsRefs ++ propertiesRangeRefs).map { id => + findNamespace(id) match { + case Some(vocab) => vocab + case None => + throw new Exception(s"Cannot find vocabulary for URI term $id") + } } vocabularies.distinct @@ -535,8 +478,7 @@ object VocabularyExporter { } @tailrec - def computeRange(fieldType: Type, - propertyTerm: VocabPropertyTerm): VocabPropertyTerm = { + def computeRange(fieldType: Type, propertyTerm: VocabPropertyTerm): VocabPropertyTerm = { fieldType match { case Str | RegExp => propertyTerm.copy(scalarRange = Some("string")) case Int => propertyTerm.copy(scalarRange = Some("integer")) @@ -562,18 +504,12 @@ object VocabularyExporter { } def fieldToVocabProperty(field: Field): VocabPropertyTerm = { - val id = field.value.iri() - val doc = field.doc + val id = field.value.iri() + val doc = field.doc val displayName = doc.displayName val description = doc.description - val propertyTerm = VocabPropertyTerm(id, - displayName, - description, - doc.superClasses, - None, - None, - Set()) + val propertyTerm = VocabPropertyTerm(id, displayName, description, doc.superClasses, None, None, Set()) computeRange(field.`type`, propertyTerm) } @@ -596,17 +532,16 @@ object VocabularyExporter { classes = classes + (klass.id -> updatedKlass) } - def buildClassTerm(klassName: String, - modelObject: Obj): Option[VocabClassTerm] = { - val doc = modelObject.doc + def buildClassTerm(klassName: String, modelObject: Obj): Option[VocabClassTerm] = { + val doc = modelObject.doc val types = modelObject.`type`.map(_.iri()) if (types.isEmpty) { None } else { - var id = types.head + var id = types.head val displayName = doc.displayName val description = doc.description - val vocab = doc.vocabulary.filename + val vocab = doc.vocabulary.filename val superClassesInDoc = types.tail val superClassesInInhertiance = Seq(modelObject.getClass.getSuperclass) ++ modelObject.getClass.getInterfaces.toSeq @@ -616,9 +551,8 @@ object VocabularyExporter { parseMetaObject(singletonKlassName) case _ => None - } collect { case Some(classTerm: VocabClassTerm) => classTerm } map { - classTerm: VocabClassTerm => - classTerm.id + } collect { case Some(classTerm: VocabClassTerm) => classTerm } map { classTerm: VocabClassTerm => + classTerm.id } var finalSuperclasses = @@ -628,7 +562,7 @@ object VocabularyExporter { var classTerm = if (klassName == "amf.core.internal.metamodel.domain.ShapeModel$") { val shapesShape = (Namespace.Shapes + "Shape").iri() - val tmp = finalSuperclasses.filter(_ != shapesShape) + val tmp = finalSuperclasses.filter(_ != shapesShape) finalSuperclasses = id :: tmp id = shapesShape VocabClassTerm(id = shapesShape, @@ -642,7 +576,7 @@ object VocabularyExporter { superClasses = finalSuperclasses) } - classes = classes + (id -> classTerm) + classes = classes + (id -> classTerm) classToFile = classToFile + (id -> vocab) /// index fields @@ -694,9 +628,9 @@ object VocabularyExporter { def createFileWriter: ExportedVocabulary => Unit = exported => { val ExportedVocabulary(vocab, export) = exported - val path = getVocabularyFileUrl(vocab) - val f = new File(path) - val writer = new FileWriter(f) + val path = getVocabularyFileUrl(vocab) + val f = new File(path) + val writer = new FileWriter(f) try { writer.write(export) } finally { @@ -713,11 +647,14 @@ object VocabularyExporter { } } - def dumpVocabularies(writeVocabulary: ExportedVocabulary => Unit, vocabularies: Seq[ModelVocabulary] = exportableVocabularies, logger: Logger): Unit = { + def dumpVocabularies(writeVocabulary: ExportedVocabulary => Unit, + vocabularies: Seq[ModelVocabulary] = exportableVocabularies, + logger: Logger): Unit = { generateVocabularies(vocabularies, logger).foreach(exported => writeVocabulary(exported)) } - private def generateVocabularies(vocabularies: Seq[ModelVocabulary] = exportableVocabularies, logger: Logger): Seq[ExportedVocabulary] = { + private def generateVocabularies(vocabularies: Seq[ModelVocabulary] = exportableVocabularies, + logger: Logger): Seq[ExportedVocabulary] = { logger.log("*** Starting") // let's initialize the files diff --git a/exporters/src/test/scala/amf/exporters/VocabularyPropertiesTest.scala b/exporters/src/test/scala/amf/exporters/VocabularyPropertiesTest.scala index c28a77a..e9f9b22 100644 --- a/exporters/src/test/scala/amf/exporters/VocabularyPropertiesTest.scala +++ b/exporters/src/test/scala/amf/exporters/VocabularyPropertiesTest.scala @@ -22,7 +22,7 @@ class VocabularyPropertiesTest extends AsyncFunSuite with VocabularyTest { } test("Vocabularies parsing aml_meta") { - testVocabulary(aml_meta, 26, 38) + testVocabulary(aml_meta, 25, 38) } test("Vocabularies parsing api_contract") { @@ -30,7 +30,7 @@ class VocabularyPropertiesTest extends AsyncFunSuite with VocabularyTest { } test("Vocabularies parsing core") { - testVocabulary(core, 4, 20) + testVocabulary(core, 9, 27) } test("Vocabularies parsing data_model") { @@ -38,7 +38,7 @@ class VocabularyPropertiesTest extends AsyncFunSuite with VocabularyTest { } test("Vocabularies parsing data_shapes") { - testVocabulary(data_shapes, 16, 46) + testVocabulary(data_shapes, 21, 57) } test("Vocabularies parsing security_model") { diff --git a/transform/dependencies.properties b/transform/dependencies.properties index bf5a5d7..7a2bf83 100644 --- a/transform/dependencies.properties +++ b/transform/dependencies.properties @@ -1,4 +1,4 @@ # Leave here for the publication process to detect if amf-transform has to be published! # Because we publish a version of amf-transform for each version of amf-client publish. -amf.apicontract=5.0.6 -amf.rdf=6.0.6 +amf.apicontract=5.0.8 +amf.rdf=6.0.8 diff --git a/transform/src/main/scala/amf/transform/internal/canonical/DomainElementTransform.scala b/transform/src/main/scala/amf/transform/internal/canonical/DomainElementTransform.scala index fb34672..5e55b49 100644 --- a/transform/src/main/scala/amf/transform/internal/canonical/DomainElementTransform.scala +++ b/transform/src/main/scala/amf/transform/internal/canonical/DomainElementTransform.scala @@ -59,12 +59,24 @@ trait DomainElementTransform extends AnnotationTransform with TransformHelpers { !dialectNode.endsWith("#/declarations/Settings") } + def isNotAbstractNode(dialectNode: DialectNode) = { + val abstractNodesSuffixes = Seq( + "#/declarations/AbstractResponse", + "#/declarations/AbstractRequest", + "#/declarations/AbstractParameter", + "#/declarations/AbstractPayload", + "#/declarations/AbstractOperation" + ) + + !abstractNodesSuffixes.exists(suffix => dialectNode.endsWith(suffix)) + } + while (typesIterator.hasNext) { val nextType = typesIterator.next().asResource().getURI mapping.get(nextType) match { case Some(dialectNode) => // dealing with inheritance here - if (isNotShape(dialectNode) && isNotApi(dialectNode) && isNotSetting(dialectNode)) { + if (isNotShape(dialectNode) && isNotApi(dialectNode) && isNotSetting(dialectNode) && isNotAbstractNode(dialectNode)) { found = true mappedDialectNode = dialectNode } else if (dialectNode.endsWith("#/declarations/Shape")) { diff --git a/transform/src/test/resources/client/webapi.canonical.jsonld b/transform/src/test/resources/client/webapi.canonical.jsonld index 578e167..6a38da7 100644 --- a/transform/src/test/resources/client/webapi.canonical.jsonld +++ b/transform/src/test/resources/client/webapi.canonical.jsonld @@ -178,13 +178,13 @@ "meta:DialectDomainElement", "raml-doc:DomainElement" ], - "core:description": "an operation", "apiContract:returns": [ { "@id": "#/web-api/endpoint/%2Ftest/supportedOperation/get/returns/resp/200" } ], - "apiContract:method": "get" + "apiContract:method": "get", + "core:description": "an operation" }, { "@id": "#/web-api/endpoint/%2Ftest/supportedOperation/get/returns/resp/200", @@ -194,13 +194,13 @@ "meta:DialectDomainElement", "raml-doc:DomainElement" ], - "apiContract:statusCode": "200", - "core:name": "200", "apiContract:payload": [ { "@id": "#/web-api/endpoint/%2Ftest/supportedOperation/get/returns/resp/200/payload/application%2Fjson" } - ] + ], + "apiContract:statusCode": "200", + "core:name": "200" }, { "@id": "#/web-api/endpoint/%2Ftest/supportedOperation/get/returns/resp/200/payload/application%2Fjson", diff --git a/transform/src/test/resources/transformations/annotations/webapi.json b/transform/src/test/resources/transformations/annotations/webapi.json index 3dfbc84..6097bba 100644 --- a/transform/src/test/resources/transformations/annotations/webapi.json +++ b/transform/src/test/resources/transformations/annotations/webapi.json @@ -412,13 +412,13 @@ "http://a.ml/vocabularies/meta#DialectDomainElement", "http://a.ml/vocabularies/document#DomainElement" ], - "http://a.ml/vocabularies/core#description": "an operation", "http://a.ml/vocabularies/apiContract#returns": [ { "@id": "file://transform/src/test/resources/transformations/annotations/api.raml#/web-api/endpoint/%2Ftest/supportedOperation/get/returns/resp/200" } ], - "http://a.ml/vocabularies/apiContract#method": "get" + "http://a.ml/vocabularies/apiContract#method": "get", + "http://a.ml/vocabularies/core#description": "an operation" }, { "@id": "file://transform/src/test/resources/transformations/annotations/api.raml#/declares/clearanceLevel/shape/schema/property/property/signature/scalar/signature", @@ -545,13 +545,13 @@ "http://a.ml/vocabularies/meta#DialectDomainElement", "http://a.ml/vocabularies/document#DomainElement" ], - "http://a.ml/vocabularies/apiContract#statusCode": "200", - "http://a.ml/vocabularies/core#name": "200", "http://a.ml/vocabularies/apiContract#payload": [ { "@id": "file://transform/src/test/resources/transformations/annotations/api.raml#/web-api/endpoint/%2Ftest/supportedOperation/get/returns/resp/200/payload/application%2Fjson" } ], + "http://a.ml/vocabularies/apiContract#statusCode": "200", + "http://a.ml/vocabularies/core#name": "200", "http://a.ml/vocabularies/document#designAnnotation": [ { "@id": "file://transform/src/test/resources/transformations/annotations/api.raml#/web-api/endpoint/%2Ftest/supportedOperation/get/returns/resp/200_annotations_1" diff --git a/transform/src/test/resources/transformations/fragments/raml/security-scheme/webapi.json b/transform/src/test/resources/transformations/fragments/raml/security-scheme/webapi.json index ff707d1..9cb99cf 100644 --- a/transform/src/test/resources/transformations/fragments/raml/security-scheme/webapi.json +++ b/transform/src/test/resources/transformations/fragments/raml/security-scheme/webapi.json @@ -68,9 +68,9 @@ ], "http://a.ml/vocabularies/apiContract#required": true, "http://a.ml/vocabularies/apiContract#paramName": "access_token", + "http://a.ml/vocabularies/apiContract#binding": "query", "http://a.ml/vocabularies/core#name": "access_token", "http://a.ml/vocabularies/core#description": "Used to send a valid OAuth 2 access token. Do not use together with the \"Authorization\" header.\n", - "http://a.ml/vocabularies/apiContract#binding": "query", "http://a.ml/vocabularies/shapes#schema": { "@id": "file://transform/src/test/resources/transformations/fragments/raml/security-scheme/api.raml#/scheme/fragment/parameter/parameter/query/access_token/scalar/schema" } @@ -83,9 +83,9 @@ "http://a.ml/vocabularies/meta#DialectDomainElement", "http://a.ml/vocabularies/document#DomainElement" ], + "http://a.ml/vocabularies/core#description": "Bad OAuth request (wrong consumer key, bad nonce, expired timestamp...). Unfortunately, re-authenticating the user won't help here.\n", "http://a.ml/vocabularies/apiContract#statusCode": "403", - "http://a.ml/vocabularies/core#name": "403", - "http://a.ml/vocabularies/core#description": "Bad OAuth request (wrong consumer key, bad nonce, expired timestamp...). Unfortunately, re-authenticating the user won't help here.\n" + "http://a.ml/vocabularies/core#name": "403" }, { "@id": "file://transform/src/test/resources/transformations/fragments/raml/security-scheme/api.raml#/scheme/fragment/response/resp/401", @@ -95,9 +95,9 @@ "http://a.ml/vocabularies/meta#DialectDomainElement", "http://a.ml/vocabularies/document#DomainElement" ], + "http://a.ml/vocabularies/core#description": "Bad or expired token. This can happen if the API consumer uses a revoked or expired access token. To fix, you should re-authenticate the user.\n", "http://a.ml/vocabularies/apiContract#statusCode": "401", - "http://a.ml/vocabularies/core#name": "401", - "http://a.ml/vocabularies/core#description": "Bad or expired token. This can happen if the API consumer uses a revoked or expired access token. To fix, you should re-authenticate the user.\n" + "http://a.ml/vocabularies/core#name": "401" }, { "@id": "file://transform/src/test/resources/transformations/fragments/raml/security-scheme/api.raml#/scheme/fragment/settings/oauth2", @@ -126,9 +126,9 @@ ], "http://a.ml/vocabularies/apiContract#required": true, "http://a.ml/vocabularies/apiContract#paramName": "Authorization", + "http://a.ml/vocabularies/apiContract#binding": "header", "http://a.ml/vocabularies/core#name": "Authorization", "http://a.ml/vocabularies/core#description": "Used to send a valid OAuth 2 access token. Do not use with the \"access_token\" query. string parameter.\n", - "http://a.ml/vocabularies/apiContract#binding": "header", "http://a.ml/vocabularies/shapes#schema": { "@id": "file://transform/src/test/resources/transformations/fragments/raml/security-scheme/api.raml#/scheme/fragment/header/parameter/header/Authorization/scalar/schema" } diff --git a/transform/src/test/resources/transformations/modular/webapi.json b/transform/src/test/resources/transformations/modular/webapi.json index 391f60e..9793c64 100644 --- a/transform/src/test/resources/transformations/modular/webapi.json +++ b/transform/src/test/resources/transformations/modular/webapi.json @@ -273,13 +273,13 @@ "http://a.ml/vocabularies/meta#DialectDomainElement", "http://a.ml/vocabularies/document#DomainElement" ], - "http://a.ml/vocabularies/core#description": "an operation", "http://a.ml/vocabularies/apiContract#returns": [ { "@id": "file://transform/src/test/resources/transformations/modular/api.raml#/web-api/endpoint/%2Ftest/supportedOperation/get/returns/resp/200" } ], - "http://a.ml/vocabularies/apiContract#method": "get" + "http://a.ml/vocabularies/apiContract#method": "get", + "http://a.ml/vocabularies/core#description": "an operation" }, { "@id": "file://transform/src/test/resources/transformations/modular/api.raml#/references/1/shape/type/property/property/p2", @@ -381,13 +381,13 @@ "http://a.ml/vocabularies/meta#DialectDomainElement", "http://a.ml/vocabularies/document#DomainElement" ], - "http://a.ml/vocabularies/apiContract#statusCode": "200", - "http://a.ml/vocabularies/core#name": "200", "http://a.ml/vocabularies/apiContract#payload": [ { "@id": "file://transform/src/test/resources/transformations/modular/api.raml#/web-api/endpoint/%2Ftest/supportedOperation/get/returns/resp/200/payload/application%2Fjson" } - ] + ], + "http://a.ml/vocabularies/apiContract#statusCode": "200", + "http://a.ml/vocabularies/core#name": "200" }, { "@id": "file://transform/src/test/resources/transformations/modular/api.raml#/references/1/shape/type/property/property/p2/scalar/p2", diff --git a/transform/src/test/resources/transformations/operation-trait/webapi.json b/transform/src/test/resources/transformations/operation-trait/webapi.json index 01b1cd9..31a3f64 100644 --- a/transform/src/test/resources/transformations/operation-trait/webapi.json +++ b/transform/src/test/resources/transformations/operation-trait/webapi.json @@ -39,11 +39,11 @@ "http://a.ml/vocabularies/meta#DialectDomainElement", "http://a.ml/vocabularies/document#DomainElement" ], - "http://a.ml/vocabularies/core#name": "firstTrait", "http://a.ml/vocabularies/apiContract#guiSummary": "aSummary", "http://a.ml/vocabularies/apiContract#operationId": "traitThing", "http://a.ml/vocabularies/apiContract#isAbstract": true, - "http://a.ml/vocabularies/apiContract#method": "firstTrait" + "http://a.ml/vocabularies/apiContract#method": "firstTrait", + "http://a.ml/vocabularies/core#name": "firstTrait" }, { "@id": "file://transform/src/test/resources/transformations/operation-trait/api.yaml#/async-api", diff --git a/transform/src/test/resources/transformations/raml-overlay/webapi.json b/transform/src/test/resources/transformations/raml-overlay/webapi.json index 7933cb5..df7e0bd 100644 --- a/transform/src/test/resources/transformations/raml-overlay/webapi.json +++ b/transform/src/test/resources/transformations/raml-overlay/webapi.json @@ -151,8 +151,8 @@ ], "http://a.ml/vocabularies/apiContract#required": true, "http://a.ml/vocabularies/apiContract#paramName": "customer_id", - "http://a.ml/vocabularies/core#name": "customer_id", "http://a.ml/vocabularies/apiContract#binding": "path", + "http://a.ml/vocabularies/core#name": "customer_id", "http://a.ml/vocabularies/shapes#schema": { "@id": "file://transform/src/test/resources/transformations/raml-overlay/api.raml#/references/0/web-api/endpoint/%2Fbooks%2F%7Bcustomer_id%7D/parameter/parameter/path/customer_id/scalar/schema" } diff --git a/transform/src/test/resources/transformations/security/webapi.json b/transform/src/test/resources/transformations/security/webapi.json index 90abe9d..e72b2b2 100644 --- a/transform/src/test/resources/transformations/security/webapi.json +++ b/transform/src/test/resources/transformations/security/webapi.json @@ -85,9 +85,9 @@ "http://a.ml/vocabularies/meta#DialectDomainElement", "http://a.ml/vocabularies/document#DomainElement" ], + "http://a.ml/vocabularies/core#description": "Bad or expired token. This can happen if the user or Dropbox\nrevoked or expired an access token. To fix, re-authenticate\nthe user.\n", "http://a.ml/vocabularies/apiContract#statusCode": "401", - "http://a.ml/vocabularies/core#name": "401", - "http://a.ml/vocabularies/core#description": "Bad or expired token. This can happen if the user or Dropbox\nrevoked or expired an access token. To fix, re-authenticate\nthe user.\n" + "http://a.ml/vocabularies/core#name": "401" }, { "@id": "file://transform/src/test/resources/transformations/security/api.raml#/declares/scheme/oauth_2_0/settings/oauth2", @@ -118,9 +118,9 @@ ], "http://a.ml/vocabularies/apiContract#required": true, "http://a.ml/vocabularies/apiContract#paramName": "Authorization", + "http://a.ml/vocabularies/apiContract#binding": "header", "http://a.ml/vocabularies/core#name": "Authorization", "http://a.ml/vocabularies/core#description": "Used to send a valid OAuth 2 access token.\n", - "http://a.ml/vocabularies/apiContract#binding": "header", "http://a.ml/vocabularies/shapes#schema": { "@id": "file://transform/src/test/resources/transformations/security/api.raml#/declares/scheme/oauth_2_0/header/parameter/header/Authorization/scalar/schema" } @@ -197,8 +197,8 @@ ], "http://a.ml/vocabularies/apiContract#required": true, "http://a.ml/vocabularies/apiContract#paramName": "userid", - "http://a.ml/vocabularies/core#name": "userid", "http://a.ml/vocabularies/apiContract#binding": "path", + "http://a.ml/vocabularies/core#name": "userid", "http://a.ml/vocabularies/shapes#schema": { "@id": "file://transform/src/test/resources/transformations/security/api.raml#/web-api/endpoint/%2Fusers%2F%7Buserid%7D%2Fgists/parameter/parameter/path/userid/scalar/userid" } diff --git a/transform/src/test/resources/transformations/semantic/obj-extension/transformed.jsonld b/transform/src/test/resources/transformations/semantic/obj-extension/transformed.jsonld index 804414a..45aa089 100644 --- a/transform/src/test/resources/transformations/semantic/obj-extension/transformed.jsonld +++ b/transform/src/test/resources/transformations/semantic/obj-extension/transformed.jsonld @@ -94,9 +94,9 @@ "meta:DialectDomainElement", "raml-doc:DomainElement" ], + "core:description": "An annotated response object with the pagination annotation.", "apiContract:statusCode": "200", "core:name": "200", - "core:description": "An annotated response object with the pagination annotation.", "raml-doc:designAnnotation": [ { "@id": "#/web-api/endpoint/%2Fv1%2Fpaginated/supportedOperation/get/returns/resp/200_annotations_0" diff --git a/transform/src/test/resources/transformations/semantic/obj-extension/transformed.rdf b/transform/src/test/resources/transformations/semantic/obj-extension/transformed.rdf index 64c97df..f33e8da 100644 --- a/transform/src/test/resources/transformations/semantic/obj-extension/transformed.rdf +++ b/transform/src/test/resources/transformations/semantic/obj-extension/transformed.rdf @@ -22,9 +22,9 @@ . . . - "An annotated response object with the pagination annotation." . "200" . "200" . + "An annotated response object with the pagination annotation." . . . . diff --git a/transform/src/test/resources/transformations/simple/webapi.json b/transform/src/test/resources/transformations/simple/webapi.json index 6b87c4f..6aa8698 100644 --- a/transform/src/test/resources/transformations/simple/webapi.json +++ b/transform/src/test/resources/transformations/simple/webapi.json @@ -178,13 +178,13 @@ "http://a.ml/vocabularies/meta#DialectDomainElement", "http://a.ml/vocabularies/document#DomainElement" ], - "http://a.ml/vocabularies/core#description": "an operation", "http://a.ml/vocabularies/apiContract#returns": [ { "@id": "file://transform/src/test/resources/transformations/simple/api.raml#/web-api/endpoint/%2Ftest/supportedOperation/get/returns/resp/200" } ], - "http://a.ml/vocabularies/apiContract#method": "get" + "http://a.ml/vocabularies/apiContract#method": "get", + "http://a.ml/vocabularies/core#description": "an operation" }, { "@id": "file://transform/src/test/resources/transformations/simple/api.raml#/web-api/endpoint/%2Ftest/supportedOperation/get/returns/resp/200", @@ -194,13 +194,13 @@ "http://a.ml/vocabularies/meta#DialectDomainElement", "http://a.ml/vocabularies/document#DomainElement" ], - "http://a.ml/vocabularies/apiContract#statusCode": "200", - "http://a.ml/vocabularies/core#name": "200", "http://a.ml/vocabularies/apiContract#payload": [ { "@id": "file://transform/src/test/resources/transformations/simple/api.raml#/web-api/endpoint/%2Ftest/supportedOperation/get/returns/resp/200/payload/application%2Fjson" } - ] + ], + "http://a.ml/vocabularies/apiContract#statusCode": "200", + "http://a.ml/vocabularies/core#name": "200" }, { "@id": "file://transform/src/test/resources/transformations/simple/api.raml#/web-api/endpoint/%2Ftest/supportedOperation/get/returns/resp/200/payload/application%2Fjson", diff --git a/transform/src/test/resources/transformations/tuple-shape-schema/webapi.json b/transform/src/test/resources/transformations/tuple-shape-schema/webapi.json index 4ec1b68..6ac2881 100644 --- a/transform/src/test/resources/transformations/tuple-shape-schema/webapi.json +++ b/transform/src/test/resources/transformations/tuple-shape-schema/webapi.json @@ -94,13 +94,13 @@ "http://a.ml/vocabularies/meta#DialectDomainElement", "http://a.ml/vocabularies/document#DomainElement" ], - "http://a.ml/vocabularies/core#description": "Returns list of claims for selcted provider", "http://a.ml/vocabularies/apiContract#returns": [ { "@id": "file://transform/src/test/resources/transformations/tuple-shape-schema/api.raml#/web-api/endpoint/%2Flist/supportedOperation/get/returns/resp/200" } ], - "http://a.ml/vocabularies/apiContract#method": "get" + "http://a.ml/vocabularies/apiContract#method": "get", + "http://a.ml/vocabularies/core#description": "Returns list of claims for selcted provider" }, { "@id": "file://transform/src/test/resources/transformations/tuple-shape-schema/api.raml#/web-api/endpoint/%2Flist/supportedOperation/get/returns/resp/200", @@ -110,13 +110,13 @@ "http://a.ml/vocabularies/meta#DialectDomainElement", "http://a.ml/vocabularies/document#DomainElement" ], - "http://a.ml/vocabularies/apiContract#statusCode": "200", - "http://a.ml/vocabularies/core#name": "200", "http://a.ml/vocabularies/apiContract#payload": [ { "@id": "file://transform/src/test/resources/transformations/tuple-shape-schema/api.raml#/web-api/endpoint/%2Flist/supportedOperation/get/returns/resp/200/payload/application%2Fjson" } - ] + ], + "http://a.ml/vocabularies/apiContract#statusCode": "200", + "http://a.ml/vocabularies/core#name": "200" }, { "@id": "file://transform/src/test/resources/transformations/tuple-shape-schema/api.raml#/web-api/endpoint/%2Flist/supportedOperation/get/returns/resp/200/payload/application%2Fjson", diff --git a/transform/src/test/scala/amf/client/ClientCanonicalTransformTest.scala b/transform/src/test/scala/amf/client/ClientCanonicalTransformTest.scala index 8ea3292..d88223e 100644 --- a/transform/src/test/scala/amf/client/ClientCanonicalTransformTest.scala +++ b/transform/src/test/scala/amf/client/ClientCanonicalTransformTest.scala @@ -18,7 +18,7 @@ class ClientCanonicalTransformTest extends AsyncFunSuite with NativeOpsFromJvm w private val environment: ExecutionEnvironment = DefaultExecutionEnvironment() implicit val context: ExecutionContext = environment._internal.context - test("Test client interfaces of the canonical transoformation") { + test("Test client interfaces of the canonical transformation") { val file = "file://transform/src/test/resources/client/api.raml" val golden = "file://transform/src/test/resources/client/webapi.canonical.jsonld" val options = new RenderOptions().withCompactUris().withSourceMaps().withPrettyPrint() diff --git a/versions.yaml b/versions.yaml index 938af32..4aed972 100644 --- a/versions.yaml +++ b/versions.yaml @@ -1,2 +1,2 @@ -amf.vocabulary: 22.0.0 -amf.transform: 2.6.0 +amf.vocabulary: 23.0.0 +amf.transform: 2.7.0 diff --git a/vocabulary/src/main/resources/dialects/canonical_webapi_spec.yaml b/vocabulary/src/main/resources/dialects/canonical_webapi_spec.yaml index 62df31f..2d76e72 100644 --- a/vocabulary/src/main/resources/dialects/canonical_webapi_spec.yaml +++ b/vocabulary/src/main/resources/dialects/canonical_webapi_spec.yaml @@ -329,6 +329,112 @@ nodeMappings: allowMultiple: true + AbstractOperation: + classTerm: core.Operation + mapping: + name: + propertyTerm: core.name + range: string + description: + propertyTerm: core.description + range: string + expects: + propertyTerm: core.expects + range: AbstractRequest + allowMultiple: true + returns: + propertyTerm: core.returns + range: AbstractResponse + allowMultiple: true + designAnnotations: + propertyTerm: doc.designAnnotation + range: DomainExtension + allowMultiple: true + + + AbstractParameter: + classTerm: core.Parameter + mapping: + name: + propertyTerm: core.name + range: string + paramName: + propertyTerm: core.paramName + range: string + binding: + propertyTerm: core.binding + range: string + description: + propertyTerm: core.description + range: string + required: + propertyTerm: core.required + range: boolean + schema: + propertyTerm: raml-shapes.schema + range: DataShapesUnion + designLink: + propertyTerm: doc.design-link-target + range: link + designAnnotations: + propertyTerm: doc.designAnnotation + range: DomainExtension + allowMultiple: true + + + AbstractPayload: + classTerm: core.Payload + mapping: + name: + propertyTerm: core.name + range: string + schema: + propertyTerm: raml-shapes.schema + range: DataShapesUnion + mediaType: + propertyTerm: core.mediaType + range: string + examples: + propertyTerm: apiContract.examples + range: Example + allowMultiple: true + designLink: + propertyTerm: doc.design-link-target + range: link + designAnnotations: + propertyTerm: doc.designAnnotation + range: DomainExtension + allowMultiple: true + + + AbstractRequest: + classTerm: core.Request + mapping: + parameter: + propertyTerm: core.parameter + range: AbstractParameter + allowMultiple: true + designAnnotations: + propertyTerm: doc.designAnnotation + range: DomainExtension + allowMultiple: true + + + AbstractResponse: + classTerm: core.Response + mapping: + name: + propertyTerm: core.name + range: string + payload: + propertyTerm: core.payload + range: AbstractPayload + designAnnotations: + propertyTerm: doc.designAnnotation + range: DomainExtension + allowMultiple: true + + Amqp091ChannelBinding: classTerm: apiBinding.Amqp091ChannelBinding extends: ChannelBinding @@ -1297,6 +1403,9 @@ nodeMappings: classTerm: shacl.NodeShape extends: AnyShape mapping: + isAbstract: + propertyTerm: raml-shapes.isAbstract + range: boolean minProperties: propertyTerm: raml-shapes.minProperties range: integer @@ -1347,6 +1456,13 @@ nodeMappings: unevaluatedPropertiesSchema: propertyTerm: raml-shapes.unevaluatedPropertiesSchema range: DataShapesUnion + supportedOperation: + propertyTerm: raml-shapes.supportedOperation + range: ShapeOperation + allowMultiple: true + inputOnly: + propertyTerm: raml-shapes.inputOnly + range: boolean OAuth1Settings: @@ -1432,6 +1548,7 @@ nodeMappings: Operation: classTerm: apiContract.Operation + extends: AbstractOperation mapping: extends: propertyTerm: doc.extends @@ -1447,12 +1564,6 @@ nodeMappings: method: propertyTerm: apiContract.method range: string - name: - propertyTerm: core.name - range: string - description: - propertyTerm: core.description - range: string deprecated: propertyTerm: core.deprecated range: boolean @@ -1510,10 +1621,6 @@ nodeMappings: designLink: propertyTerm: doc.design-link-target range: link - designAnnotations: - propertyTerm: doc.designAnnotation - range: DomainExtension - allowMultiple: true OperationBinding: @@ -1572,16 +1679,11 @@ nodeMappings: Parameter: classTerm: apiContract.Parameter + extends: AbstractParameter mapping: - name: - propertyTerm: core.name - range: string paramName: propertyTerm: apiContract.paramName range: string - description: - propertyTerm: core.description - range: string required: propertyTerm: apiContract.required range: boolean @@ -1603,9 +1705,6 @@ nodeMappings: binding: propertyTerm: apiContract.binding range: string - schema: - propertyTerm: raml-shapes.schema - range: DataShapesUnion payload: propertyTerm: apiContract.payload range: Payload @@ -1614,13 +1713,6 @@ nodeMappings: propertyTerm: apiContract.examples range: Example allowMultiple: true - designLink: - propertyTerm: doc.design-link-target - range: link - designAnnotations: - propertyTerm: doc.designAnnotation - range: DomainExtension - allowMultiple: true ParametrizedDeclaration: @@ -1672,34 +1764,15 @@ nodeMappings: Payload: classTerm: apiContract.Payload + extends: AbstractPayload mapping: - name: - propertyTerm: core.name - range: string - mediaType: - propertyTerm: core.mediaType - range: string schemaMediaType: propertyTerm: apiContract.schemaMediaType range: string - schema: - propertyTerm: raml-shapes.schema - range: DataShapesUnion - examples: - propertyTerm: apiContract.examples - range: Example - allowMultiple: true encoding: propertyTerm: apiContract.encoding range: Encoding allowMultiple: true - designLink: - propertyTerm: doc.design-link-target - range: link - designAnnotations: - propertyTerm: doc.designAnnotation - range: DomainExtension - allowMultiple: true PayloadFragment: @@ -1771,8 +1844,13 @@ nodeMappings: Request: classTerm: apiContract.Request - extends: Message + extends: AbstractRequest mapping: + extends: + propertyTerm: doc.extends + range: Message + allowMultiple: true + required: propertyTerm: apiContract.required range: boolean @@ -1791,6 +1869,59 @@ nodeMappings: propertyTerm: apiContract.cookieParameter range: Parameter allowMultiple: true + name: + propertyTerm: core.name + range: string + description: + propertyTerm: core.description + range: string + payload: + propertyTerm: apiContract.payload + range: Payload + allowMultiple: true + correlationId: + propertyTerm: core.correlationId + range: CorrelationId + displayName: + propertyTerm: core.displayName + range: string + title: + propertyTerm: core.title + range: string + summary: + propertyTerm: core.summary + range: string + header: + propertyTerm: apiContract.header + range: Parameter + allowMultiple: true + binding: + propertyTerm: apiBinding.binding + range: MessageBindings + tag: + propertyTerm: apiContract.tag + range: Tag + allowMultiple: true + examples: + propertyTerm: apiContract.examples + range: Example + allowMultiple: true + documentation: + propertyTerm: core.documentation + range: CreativeWork + isAbstract: + propertyTerm: apiContract.isAbstract + range: boolean + headerExamples: + propertyTerm: apiContract.headerExamples + range: Example + allowMultiple: true + headerSchema: + propertyTerm: apiContract.headerSchema + range: NodeShape + designLink: + propertyTerm: doc.design-link-target + range: link ResourceType: @@ -1805,8 +1936,13 @@ nodeMappings: Response: classTerm: apiContract.Response - extends: Message + extends: AbstractResponse mapping: + extends: + propertyTerm: doc.extends + range: Message + allowMultiple: true + statusCode: propertyTerm: apiContract.statusCode range: string @@ -1814,6 +1950,56 @@ nodeMappings: propertyTerm: apiContract.link range: TemplatedLink allowMultiple: true + description: + propertyTerm: core.description + range: string + payload: + propertyTerm: apiContract.payload + range: Payload + allowMultiple: true + correlationId: + propertyTerm: core.correlationId + range: CorrelationId + displayName: + propertyTerm: core.displayName + range: string + title: + propertyTerm: core.title + range: string + summary: + propertyTerm: core.summary + range: string + header: + propertyTerm: apiContract.header + range: Parameter + allowMultiple: true + binding: + propertyTerm: apiBinding.binding + range: MessageBindings + tag: + propertyTerm: apiContract.tag + range: Tag + allowMultiple: true + examples: + propertyTerm: apiContract.examples + range: Example + allowMultiple: true + documentation: + propertyTerm: core.documentation + range: CreativeWork + isAbstract: + propertyTerm: apiContract.isAbstract + range: boolean + headerExamples: + propertyTerm: apiContract.headerExamples + range: Example + allowMultiple: true + headerSchema: + propertyTerm: apiContract.headerSchema + range: NodeShape + designLink: + propertyTerm: doc.design-link-target + range: link ScalarNode: @@ -2141,6 +2327,59 @@ nodeMappings: allowMultiple: true + ShapeOperation: + classTerm: raml-shapes.Operation + extends: AbstractOperation + mapping: + expects: + propertyTerm: raml-shapes.expects + range: ShapeRequest + allowMultiple: true + returns: + propertyTerm: raml-shapes.returns + range: ShapeResponse + allowMultiple: true + + + ShapeParameter: + classTerm: raml-shapes.Parameter + extends: AbstractParameter + mapping: + paramName: + propertyTerm: raml-shapes.paramName + range: string + binding: + propertyTerm: raml-shapes.binding + range: string + required: + propertyTerm: raml-shapes.required + range: boolean + + + ShapePayload: + classTerm: raml-shapes.Payload + extends: AbstractPayload + + + ShapeRequest: + classTerm: raml-shapes.Request + extends: AbstractRequest + mapping: + parameter: + propertyTerm: raml-shapes.parameter + range: ShapeParameter + allowMultiple: true + + + ShapeResponse: + classTerm: raml-shapes.Response + extends: AbstractResponse + mapping: + payload: + propertyTerm: raml-shapes.payload + range: ShapePayload + + Tag: classTerm: apiContract.Tag mapping: diff --git a/vocabulary/src/main/resources/vocabularies/aml_meta.yaml b/vocabulary/src/main/resources/vocabularies/aml_meta.yaml index 9ac6e9b..e2441a0 100644 --- a/vocabulary/src/main/resources/vocabularies/aml_meta.yaml +++ b/vocabulary/src/main/resources/vocabularies/aml_meta.yaml @@ -11,11 +11,6 @@ classTerms: displayName: AnyMapping description: Base class for all mappings stored in the AML graph model extends: shacl.Shape - ConditionalNodeMapping: - displayName: ConditionalNodeMapping - extends: - - shacl.Shape - - AnyMapping ContextBaseIri: displayName: baseIRIModel description: Encodes information about the base document IRI for the model element @ids diff --git a/vocabulary/src/main/resources/vocabularies/api_contract.yaml b/vocabulary/src/main/resources/vocabularies/api_contract.yaml index 8dabaec..4047e8d 100644 --- a/vocabulary/src/main/resources/vocabularies/api_contract.yaml +++ b/vocabulary/src/main/resources/vocabularies/api_contract.yaml @@ -60,6 +60,7 @@ classTerms: Operation: displayName: Operation description: Action that can be executed using a particular HTTP invocation + extends: core.Operation Overlay: displayName: Overlay description: Model defining a RAML overlay @@ -72,6 +73,7 @@ classTerms: Parameter: displayName: Parameter description: Piece of data required or returned by an Operation + extends: core.Parameter ParametrizedResourceType: displayName: ParametrizedResourceType description: RAML resource type that can accept parameters @@ -83,6 +85,7 @@ classTerms: Payload: displayName: Payload description: Encoded payload using certain media-type + extends: core.Payload PayloadFragment: displayName: PayloadFragment description: Fragment encoding HTTP payload information @@ -92,7 +95,9 @@ classTerms: Request: displayName: Request description: Request information for an operation - extends: Message + extends: + - core.Request + - Message ResourceType: displayName: ResourceType description: Type of document base unit encoding a RAML resource type @@ -106,7 +111,9 @@ classTerms: Response: displayName: Response description: Response information for an operation - extends: Message + extends: + - core.Response + - Message Server: displayName: Server description: Information about the network accessible locations where the API is available diff --git a/vocabulary/src/main/resources/vocabularies/core.yaml b/vocabulary/src/main/resources/vocabularies/core.yaml index 1fadc25..4de0c6f 100644 --- a/vocabulary/src/main/resources/vocabularies/core.yaml +++ b/vocabulary/src/main/resources/vocabularies/core.yaml @@ -12,10 +12,29 @@ classTerms: License: displayName: License description: Licensing information for a resource + Operation: + displayName: AbstractOperation + description: Action that can be executed over the data of a particular shape Organization: displayName: Organization description: Organization providing an good or service + Parameter: + displayName: AbstractParameter + description: Piece of data required or returned by an Operation + Payload: + displayName: AbstractPayload + description: Encoded payload using certain media-type + Request: + displayName: AbstractRequest + description: Request information for an operation + Response: + displayName: AbstractResponse + description: Response information for an operation propertyTerms: + binding: + displayName: binding + description: Part of the Request model where the parameter can be encoded (header, path, query param, etc.) + range: string comment: displayName: comment description: A comment on an item. The comment's content is expressed via the text @@ -44,6 +63,10 @@ propertyTerms: displayName: email description: Contact email for the organization range: string + expects: + displayName: expects + description: Request information required by the operation + range: Request extensionName: displayName: name description: Name of an extension entity @@ -68,10 +91,31 @@ propertyTerms: displayName: displayName description: Human readable name for the term range: string + paramName: + displayName: paramName + description: Name of a parameter + extends: name + range: string + parameter: + displayName: parameter + description: Parameters associated to the communication model + range: Parameter + payload: + displayName: payload + description: Payload for a Request/Response + range: Payload provider: displayName: provider description: Organization providing some kind of asset or service range: Organization + required: + displayName: required + description: Marks the parameter as required + range: boolean + returns: + displayName: returns + description: Response data returned by the operation + range: Response summary: displayName: summary description: Human readable short description of the request/response diff --git a/vocabulary/src/main/resources/vocabularies/data_model.yaml b/vocabulary/src/main/resources/vocabularies/data_model.yaml index 0ac239f..33e1287 100644 --- a/vocabulary/src/main/resources/vocabularies/data_model.yaml +++ b/vocabulary/src/main/resources/vocabularies/data_model.yaml @@ -9,20 +9,20 @@ uses: rdf: external/rdf.yaml classTerms: Array: - displayName: Array Node + displayName: ArrayNode description: Node that represents a dynamic array data structure extends: - rdf.Seq - Node Link: - displayName: Link Node + displayName: LinkNode description: Node that represents a dynamic link in a data structure extends: Node Node: - displayName: Data Node + displayName: DataNode description: Base class for all data nodes parsed from the data structure Object: - displayName: Object Node + displayName: ObjectNode description: Node that represents a dynamic object with records data structure extends: Node Property: @@ -30,7 +30,7 @@ classTerms: description: Node that represents a dynamic property in a dynamic node extends: Node Scalar: - displayName: Scalar Node + displayName: ScalarNode description: Node that represents a dynamic scalar value data structure extends: Node propertyTerms: diff --git a/vocabulary/src/main/resources/vocabularies/data_shapes.yaml b/vocabulary/src/main/resources/vocabularies/data_shapes.yaml index ddb5be5..b27b323 100644 --- a/vocabulary/src/main/resources/vocabularies/data_shapes.yaml +++ b/vocabulary/src/main/resources/vocabularies/data_shapes.yaml @@ -5,6 +5,7 @@ usage: Vocabulary defining data shapes, used as an extension to SHACL uses: shacl: external/shacl.yaml doc: aml_doc.yaml + core: core.yaml apiContract: api_contract.yaml classTerms: AnyShape: @@ -38,12 +39,32 @@ classTerms: displayName: NilShape description: Data shape representing the null/nil value in the input schema extends: AnyShape + Operation: + displayName: ShapeOperation + description: Action that can be executed over the data of a particular shape + extends: core.Operation + Parameter: + displayName: ShapeParameter + description: Piece of data required or returned by an Operation + extends: core.Parameter + Payload: + displayName: ShapePayload + description: Encoded payload using certain media-type + extends: core.Payload PropertyDependencies: displayName: PropertyDependencies description: Dependency between sets of property shapes RecursiveShape: displayName: RecursiveShape description: Recursion on a Shape structure, used when expanding a shape and finding the canonical representation of that shape. + Request: + displayName: ShapeRequest + description: Request information for an operation + extends: core.Request + Response: + displayName: ShapeResponse + description: Response information for an operation + extends: core.Response ScalarShape: displayName: ScalarShape description: Data shape describing a scalar value in the input data model, reified as an scalar node in the mapped graph @@ -84,6 +105,10 @@ propertyTerms: displayName: anyOf description: Data shapes in the union range: shacl.Shape + binding: + displayName: binding + description: Part of the Request model where the parameter can be encoded (header, path, query param, etc.) + range: string closedItems: displayName: closedItems description: Constraint limiting additional shapes in the collection @@ -136,6 +161,10 @@ propertyTerms: displayName: encoding description: Describes the contents' value encoding range: string + expects: + displayName: expects + description: Request information required by the operation + range: Request fileType: displayName: fileType description: Type of file described by this shape @@ -152,6 +181,14 @@ propertyTerms: displayName: inherits description: Relationship of inheritance between data shapes range: shacl.Shape + inputOnly: + displayName: inputOnly + description: Indicates if the shape is used as schema for input data only + range: boolean + isAbstract: + displayName: isAbstract + description: Marks this shape as an abstract node shape declared for pure re-use + range: boolean items: displayName: items description: Shapes contained in the Tuple Shape @@ -172,10 +209,26 @@ propertyTerms: displayName: multiple of description: Multiple of constraint range: double + name: + displayName: name + range: string + paramName: + displayName: paramName + description: Name of a parameter + extends: name + range: string + parameter: + displayName: parameter + description: Parameters associated to the communication model + range: Parameter patternName: displayName: patternName description: Patterned property constraint range: string + payload: + displayName: payload + description: Payload for a Request/Response + range: Payload propertySource: displayName: propertySource description: Source property name in the dependency @@ -192,6 +245,14 @@ propertyTerms: displayName: readOnly description: Read only property constraint range: boolean + required: + displayName: required + description: Marks the parameter as required + range: boolean + returns: + displayName: returns + description: Response data returned by the operation + range: Response schema: displayName: schema description: Schema for an entity @@ -212,6 +273,10 @@ propertyTerms: displayName: serializationSchema description: Serialization schema for a shape range: shacl.Shape + supportedOperation: + displayName: supportedOperation + description: Supported operations for this shape + range: Operation unevaluatedItems: displayName: unevaluatedItems description: Accepts that items may not be evaluated in schema validation diff --git a/vocabulary/src/main/resources/vocabularies/external/shacl.yaml b/vocabulary/src/main/resources/vocabularies/external/shacl.yaml index c40e70e..5be3120 100644 --- a/vocabulary/src/main/resources/vocabularies/external/shacl.yaml +++ b/vocabulary/src/main/resources/vocabularies/external/shacl.yaml @@ -60,6 +60,10 @@ propertyTerms: displayName: in description: Enumeration of possible values for a data shape property range: data.Node + mandatory: + displayName: mandatory + description: Mandatory constraint over the property. Different from minCount because it only checks the presence of property + range: boolean maxCount: displayName: maxCount description: Maximum count property constraint