Skip to content

Commit

Permalink
Merge pull request #522 from aml-org/publish-6.0.8
Browse files Browse the repository at this point in the history
publish 6.0.8
  • Loading branch information
hghianni authored May 3, 2022
2 parents 0a23ce9 + 8082dc6 commit 71ca96d
Show file tree
Hide file tree
Showing 39 changed files with 2,467 additions and 116 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,96 +24,101 @@ case class PropertyMapping(override private[amf] val _internal: InternalProperty
@JSExportTopLevel("PropertyMapping")
def this() = this(InternalPropertyMapping())

def name(): StrField = _internal.name()
def nodePropertyMapping(): StrField = _internal.nodePropertyMapping()
def literalRange(): StrField = _internal.literalRange()
def objectRange(): ClientList[StrField] = _internal.objectRange().asClient
def mapKeyProperty(): StrField = _internal.mapKeyProperty()
def mapValueProperty(): StrField = _internal.mapKeyProperty()
def minCount(): IntField = _internal.minCount()
def pattern(): StrField = _internal.pattern()
def minimum(): DoubleField = _internal.minimum()
def maximum(): DoubleField = _internal.maximum()
def allowMultiple(): BoolField = _internal.allowMultiple()
def enum(): ClientList[AnyField] = _internal.enum().asClient
def sorted(): BoolField = _internal.sorted()
def typeDiscriminatorName(): StrField = _internal.typeDiscriminatorName()
def externallyLinkable(): BoolField = _internal.externallyLinkable()
def mandatory(): BoolField = _internal.mandatory()
def typeDiscriminator(): ClientMap[String] = Option(_internal.typeDiscriminator()) match {
case Some(m) =>
m.foldLeft(mutable.Map[String, String]()) {
case (acc, (k, v)) =>
acc.put(k, v)
acc
}
.asClient
case None => mutable.Map[String, String]().asClient
}

def withName(name: String): PropertyMapping = {
_internal.withName(name)
this
}
def name(): StrField = _internal.name()
def withNodePropertyMapping(propertyId: String): PropertyMapping = {
_internal.withNodePropertyMapping(propertyId)
this
}
def nodePropertyMapping(): StrField = _internal.nodePropertyMapping()
def withLiteralRange(range: String): PropertyMapping = {
_internal.withLiteralRange(range)
this
}
def literalRange(): StrField = _internal.literalRange()
def withObjectRange(range: ClientList[String]): PropertyMapping = {
_internal.withObjectRange(range.asInternal)
this
}
def objectRange(): ClientList[StrField] = _internal.objectRange().asClient
def mapKeyProperty(): StrField = _internal.mapKeyProperty()
def withMapKeyProperty(key: String): PropertyMapping = {
_internal.withMapKeyProperty(key)
this
}
def mapValueProperty(): StrField = _internal.mapKeyProperty()
def withMapValueProperty(value: String): PropertyMapping = {
_internal.withMapValueProperty(value)
this
}
def minCount(): IntField = _internal.minCount()
def withMinCount(minCount: Int): PropertyMapping = {
_internal.withMinCount(minCount)
this
}
def pattern(): StrField = _internal.pattern()
def withPattern(pattern: String): PropertyMapping = {
_internal.withPattern(pattern)
this
}
def minimum(): DoubleField = _internal.minimum()
def withMinimum(min: Double): PropertyMapping = {
_internal.withMinimum(min)
this
}
def maximum(): DoubleField = _internal.maximum()
def withMaximum(max: Double): PropertyMapping = {
_internal.withMaximum(max)
this
}
def allowMultiple(): BoolField = _internal.allowMultiple()
def withAllowMultiple(allow: Boolean): PropertyMapping = {
_internal.withAllowMultiple(allow)
this
}
def enum(): ClientList[AnyField] = _internal.enum().asClient
def withEnum(values: ClientList[Any]): PropertyMapping = {
_internal.withEnum(values.asInternal)
this
}
def sorted(): BoolField = _internal.sorted()
def withSorted(sorted: Boolean): PropertyMapping = {
_internal.withSorted(sorted)
this
}
def typeDiscriminator(): ClientMap[String] = Option(_internal.typeDiscriminator()) match {
case Some(m) =>
m.foldLeft(mutable.Map[String, String]()) {
case (acc, (k, v)) =>
acc.put(k, v)
acc
}
.asClient
case None => mutable.Map[String, String]().asClient
}

def withTypeDiscriminator(typesMapping: ClientMap[String]): PropertyMapping = {
_internal.withTypeDiscriminator(typesMapping.asInternal)
this
}

def typeDiscriminatorName(): StrField = _internal.typeDiscriminatorName()

def withTypeDiscriminatorName(name: String): PropertyMapping = {
_internal.withTypeDiscriminatorName(name)
this
}

def withExternallyLinkable(linkable: Boolean): PropertyMapping = _internal.withExternallyLinkable(linkable)
def externallyLinkable(): BoolField = _internal.externallyLinkable()
def withExternallyLinkable(linkable: Boolean): PropertyMapping = {
_internal.withExternallyLinkable(linkable)
this
}
def withMandatory(mandatory: Boolean): PropertyMapping = {
_internal.withMandatory(mandatory)
this
}

def classification(): String = {
_internal.classification() match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ trait PropertyLikeMapping[M <: PropertyLikeMappingModel]
def enum(): Seq[AnyField] = fields.field(meta.Enum)
def unique(): BoolField = fields.field(meta.Unique)
def externallyLinkable(): BoolField = fields.field(meta.ExternallyLinkable)
def mandatory(): BoolField = fields.field(meta.Mandatory)
def nodesInRange: Seq[String] = {
val range = objectRange()
if (range.isEmpty) {
Expand All @@ -45,10 +46,13 @@ trait PropertyLikeMapping[M <: PropertyLikeMappingModel]
def withSorted(sorted: Boolean): this.type = set(meta.Sorted, sorted)
def withUnique(unique: Boolean): this.type = set(meta.Unique, unique)
def withExternallyLinkable(linkable: Boolean): this.type = set(meta.ExternallyLinkable, linkable)
def withMandatory(mandatory: Boolean): this.type = set(meta.Mandatory, mandatory)

def classification(): PropertyClassification = PropertyLikeMappingClassifier.classification(this)

def toField(): Field = PropertyLikeMappingToFieldConverter.convert(this)

private[amf] def isMultiple: Boolean = allowMultiple().option().getOrElse(false)

def meta: M
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
package amf.aml.internal.metamodel.domain

import amf.core.client.scala.vocabulary.Namespace
import amf.core.internal.metamodel.Field
import amf.core.internal.metamodel.Type.{Any, Bool, Double, Int, Iri, SortedArray, Str}
import amf.core.internal.metamodel.domain.{
DataNodeModel,
DomainElementModel,
ExternalModelVocabularies,
ModelDoc,
ModelVocabularies
}
import amf.core.client.scala.vocabulary.Namespace
import amf.core.internal.metamodel.domain.{DomainElementModel, ExternalModelVocabularies, ModelDoc, ModelVocabularies}

/**
* Mappings form with which graph properties can be derived (annotation mappings, property mappings)
Expand Down Expand Up @@ -84,4 +78,14 @@ trait PropertyLikeMappingModel extends DomainElementModel with HasObjectRangeMod
Namespace.Meta + "externallyLinkable",
ModelDoc(ModelVocabularies.Meta, "linkable", "Marks this object property as supporting external links")
)

val Mandatory: Field = Field(
Bool,
Namespace.Shacl + "mandatory",
ModelDoc(
ExternalModelVocabularies.Shacl,
"mandatory",
"Mandatory constraint over the property. Different from minCount because it only checks the presence of property"
)
)
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
package amf.aml.internal.metamodel.domain

import amf.core.internal.metamodel.Field
import amf.core.internal.metamodel.Type.{Any, Bool, Double, Int, Iri, SortedArray, Str}
import amf.core.internal.metamodel.domain.{
DomainElementModel,
ExternalModelVocabularies,
ModelDoc,
ModelVocabularies,
ShapeModel
}
import amf.aml.client.scala.model.domain.PropertyMapping
import amf.core.client.scala.model.domain.AmfObject
import amf.core.client.scala.vocabulary.{Namespace, ValueType}
import amf.aml.client.scala.model.domain.PropertyMapping
import amf.core.internal.metamodel.Field
import amf.core.internal.metamodel.Type.{Iri, Str}
import amf.core.internal.metamodel.domain.{DomainElementModel, ModelDoc, ModelVocabularies, ShapeModel}

object PropertyMappingModel
extends DomainElementModel
Expand Down Expand Up @@ -50,7 +44,7 @@ object PropertyMappingModel
NodePropertyMapping :: Name :: LiteralRange :: ObjectRange ::
MapKeyProperty :: MapValueProperty :: MapTermKeyProperty :: MapTermValueProperty ::
MinCount :: Pattern :: Minimum :: Maximum :: AllowMultiple :: Sorted :: Enum :: TypeDiscriminator ::
Unique :: ExternallyLinkable :: TypeDiscriminatorName :: MergePolicy :: ShapeModel.Default :: DomainElementModel.fields
Unique :: ExternallyLinkable :: Mandatory :: TypeDiscriminatorName :: MergePolicy :: ShapeModel.Default :: DomainElementModel.fields

override def modelInstance: AmfObject = PropertyMapping()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ trait DialectSyntax { this: DialectContext =>
"enum" -> false,
"typeDiscriminatorName" -> false,
"typeDiscriminator" -> false,
"unique" -> false
"unique" -> false,
"minItems" -> false
)

val annotationMapping: Map[String, Required] = propertyLikeMapping ++ Map(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,73 @@ import amf.core.internal.parser.domain.{Annotations, ScalarNode}
import amf.aml.internal.metamodel.domain.PropertyLikeMappingModel
import amf.aml.client.scala.model.domain.PropertyLikeMapping
import amf.aml.internal.parse.dialects.DialectContext
import org.yaml.model.YMap
import amf.core.internal.annotations.VirtualElement
import org.yaml.model.{YMap, YMapEntry}

import scala.language.implicitConversions

case class MandatoryParser(map: YMap, propertyLikeMapping: PropertyLikeMapping[_ <: PropertyLikeMappingModel])(
implicit val ctx: DialectContext) {
def parse(): Unit = {
map.key(
"mandatory",
entry => {
val required = ScalarNode(entry.value).boolean().toBool
val value = if (required) 1 else 0
propertyLikeMapping.set(propertyLikeMapping.meta.MinCount,
AmfScalar(value, Annotations(entry.value)),
Annotations(entry))
}
)

// If I have minItems and mandatory ==> minCount = minItems & mandatory = mandatory
// If I have only mandatory ==> minCount = mandatory.toInt
// If I have only minItems ==> minCount = minItems & mandatory = false

// This combined logic is to allow to validate empty arrays ([])

val minItems = parseMinItems
val mandatory = parseMandatory
val existsMinItems = minItems.nonEmpty
val existsMandatory = mandatory.nonEmpty

// If minItems key exists, it will always be saved in MinCount field
if (existsMinItems && propertyLikeMapping.isMultiple) {
val minItemsValue = minItems.get.value
val minItemsEntry = minItems.get.entry
propertyLikeMapping.set(propertyLikeMapping.meta.MinCount,
AmfScalar(minItemsValue, Annotations(minItemsEntry.value)),
Annotations(minItemsEntry))
}

// Mandatory key will be processed based on the presence or not of minItems key
if (existsMandatory) {
val mandatoryValue = mandatory.get.value
val mandatoryEntry = mandatory.get.entry
// If mandatory and minItems keys exist, mandatory will be saved as a boolean in Mandatory field
if (existsMinItems) {
propertyLikeMapping.set(propertyLikeMapping.meta.Mandatory,
AmfScalar(mandatoryValue.toBoolean, Annotations(mandatoryEntry.value)),
Annotations(mandatoryEntry))
} else {
// If mandatory key exists but minItems key not, mandatory will be saved in MinCount field (the original behavior)
propertyLikeMapping.set(propertyLikeMapping.meta.MinCount,
AmfScalar(mandatoryValue, Annotations(mandatoryEntry.value)),
Annotations(mandatoryEntry))
}
} else if (existsMinItems)
propertyLikeMapping.set(propertyLikeMapping.meta.Mandatory, AmfScalar(false), Annotations(VirtualElement()))
// If minItems key exists but mandatory key not, the field Mandatory will be set as false

}

private def parseMandatory: Option[ParsedEntry] = map.key("mandatory").map { entry =>
val required = ScalarNode(entry.value).boolean().toBool
val value = if (required) 1 else 0
ParsedEntry(value, entry)
}

private def parseMinItems: Option[ParsedEntry] = map.key("minItems").map { entry =>
val value = ScalarNode(entry.value).integer().toNumber.intValue()
ParsedEntry(value, entry)
}

private case class ParsedEntry(value: Int, entry: YMapEntry)

class asBoolean(i: Int) {
def toBoolean: Boolean = i == 1
}

implicit def convertIntToBoolean(i: Int): asBoolean = new asBoolean(i)

}
Loading

0 comments on commit 71ca96d

Please sign in to comment.