Skip to content

Commit

Permalink
W-11046889: validate empty definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
arielmirra committed Jul 19, 2022
1 parent 0ab74dd commit 743b6c5
Show file tree
Hide file tree
Showing 10 changed files with 151 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1589,6 +1589,27 @@ object AMFRawValidations {
owlClass = shape("ScalarShape"),
owlProperty = shape("values"),
constraint = shape("duplicatedEnumValues")
),
AMFValidation(
uri = amfParser("empty-enum"),
owlClass = shape("ScalarShape"),
owlProperty = shape("values"),
constraint = shape("emptyEnum"),
message = "Enum definitions must have at least one value"
),
AMFValidation(
uri = amfParser("empty-union"),
owlClass = shape("UnionShape"),
owlProperty = shape("AnyOf"),
constraint = shape("emptyUnion"),
message = "Union definitions must have at least one value"
),
AMFValidation(
uri = amfParser("empty-definition"),
owlClass = sh("NodeShape"),
owlProperty = sh("PropertyShape"),
constraint = shape("emptyDefinition"),
message = "Types definition must have at least one field"
)
)
override def validations(): Seq[AMFValidation] = result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import amf.core.client.scala.model.domain._
import amf.core.client.scala.model.domain.extensions.{CustomDomainProperty, DomainExtension, PropertyShape}
import amf.core.internal.annotations.SynthesizedField
import amf.core.internal.metamodel.Field
import amf.core.internal.metamodel.domain.ShapeModel
import amf.core.internal.metamodel.domain.common.NameFieldSchema
import amf.core.internal.metamodel.domain.extensions.{CustomDomainPropertyModel, PropertyShapeModel}
import amf.core.internal.utils.RegexConverter
Expand All @@ -24,16 +25,60 @@ import amf.validation.internal.shacl.custom.CustomShaclValidator.{
CustomShaclFunctions,
ValidationInfo
}

import java.util.regex.Pattern

object CustomShaclFunctions {

val listOfFunctions: List[CustomShaclFunction] = List(
new CustomShaclFunction {
override val name: String = "emptyDefinition"
override def run(element: AmfObject, validate: Option[ValidationInfo] => Unit): Unit = {
val node = element.asInstanceOf[NodeShape]
val isInterface = node.isAbstract.value()
val isInput = node.isInputOnly.value()
val isExtensionWrapper = node.and.nonEmpty
val isSchema = node.name.isNullOrEmpty
if (node.properties.isEmpty && node.operations.isEmpty) {
if (!isExtensionWrapper && !isSchema) {
val nodeType =
if (isInterface) "Interface"
else if (isInput) "Input Type"
else "Type"
validate(
Some(
ValidationInfo(
NodeShapeModel.Properties,
Some(s"$nodeType definitions must have at least one field"),
Some(element.annotations)
)
)
)
}
}
}
},
new CustomShaclFunction {
override val name: String = "emptyUnion"
override def run(element: AmfObject, validate: Option[ValidationInfo] => Unit): Unit = {
val union = element.asInstanceOf[UnionShape]
val isWrapper = union.name.isNullOrEmpty || union.or.nonEmpty
if (!isWrapper && union.anyOf.isEmpty) validate(None)
}
},
new CustomShaclFunction {
override val name: String = "emptyEnum"
override def run(element: AmfObject, validate: Option[ValidationInfo] => Unit): Unit = {
val enum = element.asInstanceOf[ScalarShape]
if (enum.fields.exists(ShapeModel.Values) && enum.values.isEmpty) validate(None)
}
},
new CustomShaclFunction {
override val name: String = "unionInvalidMembers"
override def run(element: AmfObject, validate: Option[ValidationInfo] => Unit): Unit = {
val union = element.asInstanceOf[UnionShape]
if (union.name.nonNull) {
val union = element.asInstanceOf[UnionShape]
val isWrapper = union.name.isNullOrEmpty || union.or.nonEmpty
if (!isWrapper) {
val members = union.anyOf
val invalidMembers = members.filter {
case n: NodeShape if n.isAbstract.value() => true // interfaces
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ type Query {
}

enum Season {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ModelId: file://amf-cli/shared/src/test/resources/graphql/tck/apis/invalid/empty-enum.api.graphql
Profile: GraphQL
Conforms: false
Number of results: 1

Level: Violation

- Constraint: http://a.ml/vocabularies/amf/parser#empty-enum
Message: Enum definitions must have at least one value
Severity: Violation
Target: file://amf-cli/shared/src/test/resources/graphql/tck/apis/invalid/empty-enum.api.graphql#/declares/scalar/Season
Property:
Range: [(9,0)-(9,11)]
Location:
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,9 @@ type Query {
}

type Mutation {
changeUserStatus(input_: InputType!): OutputType
changeUserStatus(input_: InputType!): String
}

input InputType {
# this is empty
}

type OutputType {
success: Boolean
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ModelId: file://amf-cli/shared/src/test/resources/graphql/tck/apis/invalid/empty-input-type.api.graphql
Profile: GraphQL
Conforms: false
Number of results: 1

Level: Violation

- Constraint: http://a.ml/vocabularies/amf/parser#empty-definition
Message: Input Type definitions must have at least one field
Severity: Violation
Target: file://amf-cli/shared/src/test/resources/graphql/tck/apis/invalid/empty-input-type.api.graphql#/declares/shape/InputType
Property: http://www.w3.org/ns/shacl#property
Range: [(14,0)-(14,15)]
Location:
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ModelId: file://amf-cli/shared/src/test/resources/graphql/tck/apis/invalid/empty-interface.api.graphql
Profile: GraphQL
Conforms: false
Number of results: 1

Level: Violation

- Constraint: http://a.ml/vocabularies/amf/parser#empty-definition
Message: Interface definitions must have at least one field
Severity: Violation
Target: file://amf-cli/shared/src/test/resources/graphql/tck/apis/invalid/empty-interface.api.graphql#/declares/shape/HasId
Property: http://www.w3.org/ns/shacl#property
Range: [(13,0)-(13,15)]
Location:
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ModelId: file://amf-cli/shared/src/test/resources/graphql/tck/apis/invalid/empty-object.api.graphql
Profile: GraphQL
Conforms: false
Number of results: 1

Level: Violation

- Constraint: http://a.ml/vocabularies/amf/parser#empty-definition
Message: Type definitions must have at least one field
Severity: Violation
Target: file://amf-cli/shared/src/test/resources/graphql/tck/apis/invalid/empty-object.api.graphql#/declares/shape/Person
Property: http://www.w3.org/ns/shacl#property
Range: [(9,0)-(9,11)]
Location:
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ModelId: file://amf-cli/shared/src/test/resources/graphql/tck/apis/invalid/empty-union.api.graphql
Profile: GraphQL
Conforms: false
Number of results: 1

Level: Violation

- Constraint: http://a.ml/vocabularies/amf/parser#empty-union
Message: Union definitions must have at least one value
Severity: Violation
Target: file://amf-cli/shared/src/test/resources/graphql/tck/apis/invalid/empty-union.api.graphql#/declares/union/SearchResult
Property:
Range: [(19,0)-(19,20)]
Location:
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,18 @@ class GraphQLNestedEnumParser(enumTypeDef: Node)(implicit val ctx: GraphQLWebApi
}

private def parseValues(): Unit = {
path(enumTypeDef, Seq(ENUM_VALUES_DEFINITION)) map { case valuesNode: Node =>
val values = collect(valuesNode, Seq(ENUM_VALUE_DEFINITION)) map { case valueDefNode: Node =>
getEnumValue(valueDefNode) match {
case Some(value: ScalarNode) =>
parseDirectives(valueDefNode, value)
value
case None => ScalarNode()
path(enumTypeDef, Seq(ENUM_VALUES_DEFINITION)) match {
case Some(valuesNode: Node) =>
val values = collect(valuesNode, Seq(ENUM_VALUE_DEFINITION)) map { case valueDefNode: Node =>
getEnumValue(valueDefNode) match {
case Some(value: ScalarNode) =>
parseDirectives(valueDefNode, value)
value
case None => ScalarNode()
}
}
}
enum.withValues(values)
enum.withValues(values)
case _ => enum.withValues(Seq())
}
}

Expand Down

0 comments on commit 743b6c5

Please sign in to comment.