Skip to content

Commit

Permalink
Merge pull request #1143 from aml-org/publish-4.7.8-master
Browse files Browse the repository at this point in the history
Publish amf 4.7.8
  • Loading branch information
looseale authored Sep 24, 2021
2 parents bf92095 + 5cb3c2f commit 9f05bc9
Show file tree
Hide file tree
Showing 13 changed files with 229 additions and 33 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,11 @@ $ sbt buildCommandLine

This will generate an executable JAR at the top level directory that can be used to execute AMF from the command line.

Using this JAR, you can run tasks from command line, for instance:
Alternatively, you can download the assembly JAR from nexus [releases](https://repository-master.mulesoft.org/nexus/content/repositories/releases/com/github/amlorg/amf-client_2.12/)
or [snapshots](https://repository-master.mulesoft.org/nexus/content/repositories/snapshots/com/github/amlorg/amf-client_2.12/),
select the desired version and download the `amf-client_2.12-x.y.z-assembly.jar` file. This JAR is already built and executable.

Using AMFs JAR, you can run tasks from command line, for instance:
```bash
$ java -jar amf-x.y.z.jar parse -in "RAML 1.0" -mime-in "application/yaml" yourAPIfile
```
Expand Down
10 changes: 10 additions & 0 deletions amf-client/js/typings/amf-client-js.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#%RAML 1.0
title: test

types:
testType: |
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"testProp": {
"type": [
"string",
"null"
],
"examples": [
"a string",
123
]
}
}
}
/ep1:
get:
responses:
200:
body:
application/json:
type: testType
example:
validTestProp: "a string"
invalidTestProp: 123
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#%RAML 1.0
title: test

types:
testType: |
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"testProp": {
"type": [
"string",
"null"
],
"examples": [
"a string",
null
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#%RAML 1.0

title: test

types:
BaseObject:
type: object
properties:
items:
type: array
items:
type: any

ArrayOfObjects:
type: object[]

CustomObjectList:
type: BaseObject
properties:
items:
type: array
items:
type: ArrayOfObjects
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#%RAML 1.0

title: test

types:
BaseObject:
type: object
properties:
items:
type: array
items: any

CustomObjectList:
type: BaseObject
properties:
items:
type: array
items: object[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Model: file://amf-client/shared/src/test/resources/validations/jsonschema/type/invalid-type-array.raml
Profile: RAML 1.0
Conforms? false
Number of results: 1

Level: Violation

- Source: http://a.ml/vocabularies/amf/validation#example-validation-error
Message: should be null
should be string
should match some schema in anyOf

Level: Violation
Target: file://amf-client/shared/src/test/resources/validations/jsonschema/type/invalid-type-array.raml#/declarations/types/testType/property/testProp/union/testProp/example/default-example_2
Property: file://amf-client/shared/src/test/resources/validations/jsonschema/type/invalid-type-array.raml#/declarations/types/testType/property/testProp/union/testProp/example/default-example_2
Position: Some(LexicalInformation([(17,19)-(17,22)]))
Location: file://amf-client/shared/src/test/resources/validations/jsonschema/type/invalid-type-array.raml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Model: file://amf-client/shared/src/test/resources/validations/jsonschema/type/invalid-type-array.raml
Profile: RAML 1.0
Conforms? false
Number of results: 1

Level: Violation

- Source: http://a.ml/vocabularies/amf/validation#example-validation-error
Message: expected type: String, found: Integer
expected: null, found: Integer

Level: Violation
Target: file://amf-client/shared/src/test/resources/validations/jsonschema/type/invalid-type-array.raml#/declarations/types/testType/property/testProp/union/testProp/example/default-example_2
Property: file://amf-client/shared/src/test/resources/validations/jsonschema/type/invalid-type-array.raml#/declarations/types/testType/property/testProp/union/testProp/example/default-example_2
Position: Some(LexicalInformation([(17,19)-(17,22)]))
Location: file://amf-client/shared/src/test/resources/validations/jsonschema/type/invalid-type-array.raml
Original file line number Diff line number Diff line change
Expand Up @@ -176,5 +176,13 @@ class JsonSchemaExampleValidationTest extends MultiPlatformReportGenTest {
validate("/dependencies/schema-dependencies.raml", Some("/dependencies/schema-dependencies.report"))
}

test("JSON Schema 7 type array with examples") {
validate("/type/type-array.raml")
}

test("JSON Schema 7 invalid example in type array") {
validate("/type/invalid-type-array.raml", Some("/type/invalid-type-array.report"))
}

override val hint: Hint = RamlYamlHint
}
Original file line number Diff line number Diff line change
Expand Up @@ -638,4 +638,12 @@ class RamlModelUniquePlatformReportTest extends UniquePlatformReportGenTest {
test("required with non-declared property and additionalProperties = false") {
validate("required-with-no-additional-props.raml", None, Raml08Profile)
}

test("override type any with type object[]") {
validate("override-any-with-array.raml")
}

test("override type any with other type that is object[]") {
validate("override-any-with-array-type.raml")
}
}
4 changes: 2 additions & 2 deletions amf-webapi.versions
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
amf.webapi=4.7.7
amf.webapi=4.7.8
amf.core=4.2.224
amf.custom.validations=5.1.9
amf.custom.validations=5.1.10
amf.model=3.1.0
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ case class InlineOasTypeParser(entryOrNode: YMapEntryLike,
}
}

def validateUnionType(): Unit =
private def validateUnionType(): Unit =
if (version.isInstanceOf[OAS30SchemaVersion])
ctx.eh.violation(InvalidJsonSchemaType,
"",
Expand Down Expand Up @@ -120,7 +120,6 @@ case class InlineOasTypeParser(entryOrNode: YMapEntryLike,
* JSON Schema allows to define multiple types for a shape.
* In this case we can parse this as a union because properties
* are going to be disjoint for each of them
* @return
*/
private def detectDisjointUnion(): Boolean = {
map.key("type").isDefined && map.key("type").get.value.asOption[YSequence].isDefined
Expand All @@ -137,43 +136,57 @@ case class InlineOasTypeParser(entryOrNode: YMapEntryLike,
private def parseDisjointUnionType(): UnionShape = {

// val detectedTypes = map.key("type").get.value.as[YSequence].nodes.map(_.as[String])
val filtered = YMap(map.entries.filter(_.key.as[String] != "type"), map.sourceName)
val allEntriesExceptType = YMap(map.entries.filter(_.key.as[String] != "type"), map.sourceName)

val parser = UnionShapeParser(YMapEntryLike(filtered), name)
val parser = UnionShapeParser(YMapEntryLike(allEntriesExceptType), name)
adopt(parser.shape) // We need to set the shape id before parsing to properly adopt nested nodes
val union = parser.parse()

val finals = filtered.entries.filter { entry =>
val prop = entry.key.as[String]
prop != "example" && prop != "examples".asOasExtension && prop != "title" &&
prop != "description" && prop != "default" && prop != "enum" &&
prop != "externalDocs" && prop != "xml" && prop != "facets".asOasExtension &&
prop != "anyOf" && prop != "allOf" && prop != "oneOf" && prop != "not"
val filterKeys = Seq(
"example",
"examples",
"examples".asOasExtension,
"title",
"description",
"default",
"enum",
"externalDocs",
"xml",
"facets".asOasExtension,
"anyOf",
"allOf",
"oneOf",
"not"
)
val filteredEntries = allEntriesExceptType.entries.filter { entry =>
!filterKeys.contains(entry.key.as[String])
}

val exclusiveProps = YMap(finals, finals.headOption.map(_.sourceName).getOrElse(""))
var i = 0
val sequence = map.key("type").get.value.as[YSequence]
val parsedTypes: Seq[AmfElement] = sequence.nodes map { node =>
i += 1
val propsToPropagate = YMap(filteredEntries, filteredEntries.headOption.map(_.sourceName).getOrElse(""))
val typesSeq = map.key("type").get.value.as[YSequence]
var index = 0
val parsedTypes: Seq[AmfElement] = typesSeq.nodes map { node =>
index += 1
if (node.tagType == YType.Str) {
node.as[String] match {
case "object" =>
Some(parseObjectType(name + i, exclusiveProps, s => s.withId(union.id + "/object")))
Some(parseObjectType(name + index, propsToPropagate, s => s.withId(union.id + "/object")))
case "array" =>
Some(parseArrayType(name + i, exclusiveProps, s => s.withId(union.id + "/array")))
Some(parseArrayType(name + index, propsToPropagate, s => s.withId(union.id + "/array")))
case "number" =>
Some(parseScalarType(TypeDef.NumberType, name + i, exclusiveProps, s => s.withId(union.id + "/number")))
Some(
parseScalarType(TypeDef.NumberType, name + index, propsToPropagate, s => s.withId(union.id + "/number")))
case "integer" =>
Some(parseScalarType(TypeDef.IntType, name + i, exclusiveProps, s => s.withId(union.id + "/integer")))
Some(
parseScalarType(TypeDef.IntType, name + index, propsToPropagate, s => s.withId(union.id + "/integer")))
case "string" =>
Some(parseScalarType(TypeDef.StrType, name + i, exclusiveProps, s => s.withId(union.id + "/string")))
Some(parseScalarType(TypeDef.StrType, name + index, propsToPropagate, s => s.withId(union.id + "/string")))
case "boolean" =>
Some(parseScalarType(TypeDef.BoolType, name + i, exclusiveProps, s => s.withId(union.id + "/boolean")))
Some(
parseScalarType(TypeDef.BoolType, name + index, propsToPropagate, s => s.withId(union.id + "/boolean")))
case "null" =>
Some(parseScalarType(TypeDef.NilType, name + i, exclusiveProps, s => s.withId(union.id + "/nil")))
Some(parseScalarType(TypeDef.NilType, name + index, propsToPropagate, s => s.withId(union.id + "/nil")))
case "any" =>
Some(parseAnyType(name + i, exclusiveProps, s => s.withId(union.id + "/any")))
Some(parseAnyType(name + index, propsToPropagate, s => s.withId(union.id + "/any")))
case other =>
ctx.eh.violation(InvalidDisjointUnionType,
union.id,
Expand All @@ -182,7 +195,7 @@ case class InlineOasTypeParser(entryOrNode: YMapEntryLike,
None
}
} else if (node.tagType == YType.Map) {
val entry = YMapEntry(s"union_member_$i", node)
val entry = YMapEntry(s"union_member_$index", node)
OasTypeParser(entry, shape => shape.adopted(union.id), version).parse()
} else {
ctx.eh.violation(InvalidDisjointUnionType,
Expand All @@ -193,7 +206,7 @@ case class InlineOasTypeParser(entryOrNode: YMapEntryLike,
}
} collect { case Some(t: AmfElement) => t }

if (parsedTypes.nonEmpty) union.setArrayWithoutId(UnionShapeModel.AnyOf, parsedTypes, Annotations(sequence))
if (parsedTypes.nonEmpty) union.setArrayWithoutId(UnionShapeModel.AnyOf, parsedTypes, Annotations(typesSeq))

union
}
Expand Down Expand Up @@ -612,10 +625,10 @@ case class InlineOasTypeParser(entryOrNode: YMapEntryLike,

private def parseExample(): Unit = {

if (version isBiggerThanOrEqualTo JSONSchemaDraft6SchemaVersion) parseExamplesArray()
if (version isBiggerThanOrEqualTo JSONSchemaDraft6SchemaVersion)
parseExamplesArray()
else
RamlExamplesParser(map, "example", "examples".asOasExtension, shape, options)
.parse()
RamlExamplesParser(map, "example", "examples".asOasExtension, shape, options).parse()
}

private def parseExamplesArray(): Unit =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ private[stages] class MinShapeAlgorithm()(implicit val context: NormalizationCon
case baseArray: MatrixShape if superShape.isInstanceOf[MatrixShape] =>
val superArray = superShape.asInstanceOf[MatrixShape]
computeMinMatrix(baseArray, superArray)
case baseArray: MatrixShape if isArrayOfAnyShapes(superShape) =>
val superArray = superShape.asInstanceOf[ArrayShape]
computeMinMatrixWithAnyShape(baseArray, superArray)
case baseArray: TupleShape if superShape.isInstanceOf[TupleShape] =>
val superArray = superShape.asInstanceOf[TupleShape]
computeMinTuple(baseArray, superArray)
Expand Down Expand Up @@ -234,6 +237,29 @@ private[stages] class MinShapeAlgorithm()(implicit val context: NormalizationCon
baseMatrix
}

protected def isArrayOfAnyShapes(shape: Shape): Boolean =
shape.isInstanceOf[ArrayShape] && shape.asInstanceOf[ArrayShape].items.isInstanceOf[AnyShape]

protected def computeMinMatrixWithAnyShape(baseMatrix: MatrixShape, superArray: ArrayShape): Shape = {

val superItems = superArray
val baseItems = baseMatrix.items
if (Option(superItems).isDefined && Option(baseItems).isDefined) {

val newItems = context.minShape(baseItems, superItems)
baseMatrix.fields.setWithoutId(ArrayShapeModel.Items, newItems)

computeNarrowRestrictions(ArrayShapeModel.fields,
baseMatrix,
superArray,
filteredFields = Seq(ArrayShapeModel.Items))
} else {
if (Option(superItems).isDefined) baseMatrix.fields.setWithoutId(ArrayShapeModel.Items, superItems)
}

baseMatrix
}

protected def computeMinTuple(baseTuple: TupleShape, superTuple: TupleShape): Shape = {
val superItems = baseTuple.items
val baseItems = superTuple.items
Expand Down Expand Up @@ -306,7 +332,7 @@ private[stages] class MinShapeAlgorithm()(implicit val context: NormalizationCon

superProperties.foreach(p => commonProps.put(p.path.value(), false))
baseProperties.foreach { p =>
if (commonProps.get(p.path.value()).isDefined) {
if (commonProps.contains(p.path.value())) {
commonProps.put(p.path.value(), true)
} else {
commonProps.put(p.path.value(), false)
Expand Down

0 comments on commit 9f05bc9

Please sign in to comment.