Skip to content

Commit 66e2d74

Browse files
authored
Merge pull request #2017 from aml-org/publish-5.5.3
W-16124325 - Publish 5.5.3
2 parents b288e5d + f3d40ef commit 66e2d74

File tree

910 files changed

+56955
-46033
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

910 files changed

+56955
-46033
lines changed

amf-api-contract/shared/src/main/scala/amf/apicontract/client/platform/AMFConfiguration.scala

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package amf.apicontract.client.platform
22

3-
import amf.aml.client.platform.model.document.Dialect
4-
import amf.aml.client.platform.model.document.DialectInstance
3+
import amf.aml.client.platform.model.document.{Dialect, DialectInstance}
54
import amf.aml.internal.convert.VocabulariesClientConverter.DialectConverter
65
import amf.apicontract.client.scala.{
76
APIConfiguration => InternalAPIConfiguration,
87
AsyncAPIConfiguration => InternalAsyncAPIConfiguration,
98
OASConfiguration => InternalOASConfiguration,
109
RAMLConfiguration => InternalRAMLConfiguration,
11-
WebAPIConfiguration => InternalWebAPIConfiguration
10+
WebAPIConfiguration => InternalWebAPIConfiguration,
11+
AvroConfiguration => InternalAvroConfiguration
1212
}
1313
import amf.apicontract.internal.convert.ApiClientConverters._
1414
import amf.core.client.platform.config.{AMFEventListener, ParsingOptions, RenderOptions}
@@ -21,8 +21,7 @@ import amf.core.internal.convert.TransformationPipelineConverter._
2121

2222
import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel}
2323
import amf.apicontract.client.scala
24-
import amf.core.client.platform.AMFGraphConfiguration
25-
import amf.core.client.platform.adoption.{IdAdopter, IdAdopterProvider}
24+
import amf.core.client.platform.adoption.IdAdopterProvider
2625
import amf.core.client.platform.execution.BaseExecutionEnvironment
2726
import amf.core.client.platform.validation.payload.AMFShapePayloadValidationPlugin
2827
import amf.core.internal.convert.PayloadValidationPluginConverter.PayloadValidationPluginMatcher
@@ -220,3 +219,10 @@ object APIConfiguration {
220219
def API(): AMFConfiguration = InternalAPIConfiguration.API()
221220
def fromSpec(spec: Spec): AMFConfiguration = InternalAPIConfiguration.fromSpec(spec)
222221
}
222+
223+
// AVRO is in alpha support mode
224+
@JSExportAll
225+
@JSExportTopLevel("AvroConfiguration")
226+
object AvroConfiguration {
227+
def Avro(): AMFConfiguration = InternalAvroConfiguration.Avro()
228+
}

amf-api-contract/shared/src/main/scala/amf/apicontract/client/scala/AMFConfiguration.scala

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import amf.apicontract.internal.convert.ApiRegister
88
import amf.apicontract.internal.entities.{APIEntities, FragmentEntities}
99
import amf.apicontract.internal.plugins.ApiContractFallbackPlugin
1010
import amf.apicontract.internal.spec.async.{Async20ElementRenderPlugin, Async20ParsePlugin, Async20RenderPlugin}
11+
import amf.apicontract.internal.spec.avro.AvroParsePlugin
1112
import amf.apicontract.internal.spec.oas._
1213
import amf.apicontract.internal.spec.raml._
1314
import amf.apicontract.internal.transformation._
@@ -156,6 +157,12 @@ object RAMLConfiguration extends APIConfigurationBuilder {
156157
}
157158
}
158159

160+
// AVRO is in alpha support mode
161+
object AvroConfiguration extends APIConfigurationBuilder {
162+
def Avro(): AMFConfiguration =
163+
common().withPlugins(List(AvroParsePlugin)) // TODO: add validation profiles and serialization
164+
}
165+
159166
/** [[APIConfigurationBuilder.common common()]] configuration with all configurations needed for OAS like:
160167
* - Validation rules
161168
* - Parse and emit plugins

amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/emitters/domain/AsyncSchemaEmitter.scala

+16-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import amf.core.client.scala.model.domain.Shape
1111
import amf.core.internal.render.BaseEmitters.pos
1212
import amf.core.internal.render.SpecOrdering
1313
import amf.core.internal.render.emitters.EntryEmitter
14-
import amf.shapes.internal.spec.common.{RAML10SchemaVersion, SchemaVersion}
14+
import amf.shapes.internal.spec.common.{AVROSchema, RAML10SchemaVersion, SchemaVersion}
1515
import amf.shapes.internal.spec.oas.emitter.OasTypePartEmitter
1616
import amf.shapes.internal.spec.raml.emitter.Raml10TypeEmitter
1717
import org.yaml.model.YDocument.EntryBuilder
@@ -27,8 +27,9 @@ case class AsyncSchemaEmitter(
2727
override def emit(b: EntryBuilder): Unit = {
2828
val schemaVersion = AsyncSchemaFormats.getSchemaVersion(mediaType)(spec.eh)
2929
schemaVersion match {
30-
case RAML10SchemaVersion => emitAsRaml(b)
31-
case _ => emitAsOas(b, schemaVersion)
30+
case RAML10SchemaVersion => emitAsRaml(b)
31+
case AVROSchema(avroType) => emitAsAvro(b, schemaVersion, avroType) // todo: is it necessary?
32+
case _ => emitAsOas(b, schemaVersion)
3233
}
3334
}
3435

@@ -53,5 +54,17 @@ case class AsyncSchemaEmitter(
5354
)
5455
}
5556

57+
private def emitAsAvro(b: EntryBuilder, schemaVersion: SchemaVersion, avroType: String): Unit = {
58+
b.entry(
59+
key,
60+
b => {
61+
val newCtx = new Async20SpecEmitterContext(spec.eh, config = spec.renderConfig, schemaVersion = schemaVersion)
62+
// todo: call a specific AVRO Schema emitter (tbd in W-15633198)
63+
OasTypePartEmitter(shape, ordering, references = references)(OasLikeShapeEmitterContextAdapter(newCtx))
64+
.emit(b)
65+
}
66+
)
67+
}
68+
5669
override def position(): Position = pos(shape.annotations)
5770
}

amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/domain/Async20EndpointParser.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class Async20EndpointParser(entry: YMapEntry, parentId: String, collector: List[
4949
"subscribe|publish",
5050
entries => {
5151
val operations = parseOperations(entries)
52-
endpoint.setWithoutId(EndPointModel.Operations, AmfArray(operations, Annotations(map)), Annotations(map))
52+
endpoint.setWithoutId(EndPointModel.Operations, AmfArray(operations, Annotations.virtual()), Annotations.virtual())
5353
}
5454
)
5555

@@ -73,7 +73,7 @@ class Async22EndpointParser(
7373
entry => {
7474
val nodes = entry.value.as[YSequence].nodes
7575
val servers = nodes.map { n =>
76-
val server = Server()
76+
val server = Server(Annotations(n))
7777
server.setWithoutId(
7878
ServerModel.Name,
7979
AmfScalar(n.toString, Annotations(n.value)),

amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/domain/AsyncApiTypeParser.scala

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package amf.apicontract.internal.spec.async.parser.domain
22

33
import amf.apicontract.client.scala.model.domain.Payload
4+
import amf.apicontract.internal.spec.avro.AvroSettings
5+
import amf.apicontract.internal.spec.avro.parser.context.AvroSchemaContext
6+
import amf.apicontract.internal.spec.avro.parser.domain.AvroShapeParser
47
import amf.apicontract.internal.spec.common.WebApiDeclarations
58
import amf.apicontract.internal.spec.oas.parser.context.OasLikeWebApiContext
69
import amf.apicontract.internal.spec.spec.toRaml
@@ -46,8 +49,8 @@ object AsyncSchemaFormats {
4649
value match {
4750
case Some(format) if oas30Schema.contains(format) => OAS30SchemaVersion(SchemaPosition.Schema)
4851
case Some(format) if ramlSchema.contains(format) => RAML10SchemaVersion
49-
// async20 schemas are handled with draft 7. Avro schema is not supported
50-
case _ => JSONSchemaDraft7SchemaVersion
52+
case Some(format) if avroSchema.contains(format) => AVROSchema()
53+
case _ => JSONSchemaDraft7SchemaVersion // async20 schemas are handled with draft 7 by default
5154
}
5255
}
5356

@@ -57,7 +60,9 @@ case class AsyncApiTypeParser(entry: YMapEntry, adopt: Shape => Unit, version: S
5760

5861
def parse(): Option[Shape] = version match {
5962
case RAML10SchemaVersion => CustomRamlReferenceParser(YMapEntryLike(entry), adopt).parse()
60-
case _ => OasTypeParser(entry, adopt, version).parse()
63+
case AVROSchema(_) =>
64+
new AvroShapeParser(YMapEntryLike(entry).asMap)(new AvroSchemaContext(ctx, AvroSettings)).parse()
65+
case _ => OasTypeParser(entry, adopt, version).parse()
6166
}
6267
}
6368

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package amf.apicontract.internal.spec.avro
2+
3+
import amf.apicontract.internal.plugins.ApiParsePlugin
4+
import amf.apicontract.internal.spec.avro.parser.context.AvroSchemaContext
5+
import amf.apicontract.internal.spec.avro.parser.document.AvroDocumentParser
6+
import amf.core.client.scala.model.document.BaseUnit
7+
import amf.core.client.scala.parse.document.ParserContext
8+
import amf.core.internal.parser.Root
9+
import amf.core.internal.remote.{Mimes, Spec}
10+
11+
object AvroParsePlugin extends ApiParsePlugin {
12+
13+
override def spec: Spec = Spec.AVRO_SCHEMA
14+
15+
override def parse(document: Root, ctx: ParserContext): BaseUnit = {
16+
new AvroDocumentParser(document)(new AvroSchemaContext(ctx, AvroSettings)).parseDocument()
17+
}
18+
19+
/** media types which specifies vendors that are parsed by this plugin. */
20+
override def mediaTypes: Seq[String] = Seq(Mimes.`application/json`)
21+
22+
override def applies(element: Root): Boolean = element.mediatype == Mimes.`application/json`
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package amf.apicontract.internal.spec.avro
2+
3+
import amf.core.client.scala.parse.document.ParserContext
4+
import amf.core.internal.plugins.syntax.SyamlAMFErrorHandler
5+
import amf.core.internal.remote.Spec
6+
import amf.core.internal.remote.Spec.AVRO_SCHEMA
7+
import amf.shapes.internal.spec.common.parser._
8+
import amf.shapes.internal.spec.common.{OAS20SchemaVersion, SchemaPosition, SchemaVersion}
9+
import amf.shapes.internal.spec.raml.parser.RamlWebApiContextType.RamlWebApiContextType
10+
import org.yaml.model.YNode
11+
12+
object AvroSettings extends SpecSettings {
13+
override val spec: Spec = AVRO_SCHEMA
14+
15+
override def link(node: YNode)(implicit eh: SyamlAMFErrorHandler): Either[String, YNode] = Left(node.toString)
16+
17+
override def ignoreCriteria: IgnoreCriteria = IgnoreAllCriteria
18+
19+
override def ramlContextType: Option[RamlWebApiContextType] = None
20+
21+
override val defaultSchemaVersion: SchemaVersion = OAS20SchemaVersion.apply(SchemaPosition.Other)
22+
override val annotationValidatorBuilder: AnnotationSchemaValidatorBuilder = IgnoreAnnotationSchemaValidatorBuilder
23+
24+
override def shouldLinkTypes(parent: ParserContext): Boolean = parent match {
25+
case ctx: ShapeParserContext if ctx.isRamlContext => false
26+
case _ => true
27+
}
28+
29+
override val syntax: SpecSyntax = SpecSyntax.empty
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package amf.apicontract.internal.spec.avro.parser.context
2+
3+
import amf.core.client.scala.parse.document.ParserContext
4+
import amf.shapes.internal.spec.common.parser.{ShapeParserContext, SpecSettings}
5+
6+
import scala.collection.mutable
7+
8+
class AvroSchemaContext(ctx: ParserContext, settings: SpecSettings)
9+
extends ShapeParserContext(
10+
ctx.rootContextDocument,
11+
ctx.refs,
12+
ctx.parsingOptions,
13+
ctx,
14+
None,
15+
mutable.Map.empty,
16+
settings
17+
) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package amf.apicontract.internal.spec.avro.parser.document
2+
3+
import amf.apicontract.internal.spec.avro.parser.context.AvroSchemaContext
4+
import amf.apicontract.internal.spec.avro.parser.domain.AvroShapeParser
5+
import amf.core.client.scala.model.document.BaseUnitProcessingData
6+
import amf.core.client.scala.parse.document.SyamlParsedDocument
7+
import amf.core.internal.metamodel.document.DocumentModel
8+
import amf.core.internal.parser.domain.Annotations
9+
import amf.core.internal.parser.{Root, YMapOps}
10+
import amf.core.internal.remote.Spec
11+
import amf.shapes.client.scala.model.document.AvroSchemaDocument
12+
import amf.shapes.client.scala.model.domain.AnyShape
13+
import amf.shapes.internal.spec.common.parser.QuickFieldParserOps
14+
import org.yaml.model.YMap
15+
16+
class AvroDocumentParser(root: Root)(implicit ctx: AvroSchemaContext) extends QuickFieldParserOps {
17+
18+
def parseDocument(): AvroSchemaDocument = {
19+
val map = root.parsed.asInstanceOf[SyamlParsedDocument].document.as[YMap]
20+
val doc = AvroSchemaDocument(Annotations(map))
21+
.withLocation(ctx.loc)
22+
.withProcessingData(BaseUnitProcessingData().withSourceSpec(Spec.AVRO_SCHEMA))
23+
24+
map.key("namespace", (DocumentModel.Package in doc).allowingAnnotations)
25+
26+
val parsedShape = parseType(map)
27+
parsedShape.foreach(shape => doc.withEncodes(shape))
28+
doc
29+
}
30+
31+
def parseType(map: YMap): Option[AnyShape] = new AvroShapeParser(map).parse()
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package amf.apicontract.internal.spec.avro.parser.domain
2+
import amf.apicontract.internal.spec.avro.parser.context.AvroSchemaContext
3+
import amf.shapes.client.scala.model.domain.{AnyShape, ArrayShape}
4+
import org.yaml.model.{YMap, YMapEntry}
5+
6+
case class AvroArrayShapeParser(map: YMap)(implicit ctx: AvroSchemaContext)
7+
extends AvroCollectionShapeParser[ArrayShape](map, "items") {
8+
override val shape: ArrayShape = ArrayShape(map)
9+
override def setMembers(anyShape: AnyShape): Unit = shape.withItems(anyShape)
10+
override def parseMembers(e: YMapEntry): AnyShape = AvroTextParser(e.value).parse()
11+
12+
override def parseSpecificFields(): Unit = {}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package amf.apicontract.internal.spec.avro.parser.domain
2+
3+
import amf.apicontract.internal.spec.avro.parser.context.AvroSchemaContext
4+
import amf.core.internal.parser.YMapOps
5+
import amf.shapes.client.scala.model.domain.AnyShape
6+
import org.yaml.model.{YMap, YMapEntry}
7+
8+
abstract class AvroCollectionShapeParser[T <: AnyShape](map: YMap, membersKey: String)(implicit ctx: AvroSchemaContext)
9+
extends AvroComplexShapeParser(map) {
10+
val shape: T
11+
12+
protected def setMembers(anyShape: AnyShape): Unit
13+
14+
override def parse(): AnyShape = {
15+
map
16+
.key(membersKey)
17+
.map(parseMembers)
18+
.foreach(setMembers)
19+
parseDefault()
20+
shape
21+
}
22+
23+
protected def parseMembers(e: YMapEntry): AnyShape = AvroTextTypeParser(e.value.as[String], None).parse()
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package amf.apicontract.internal.spec.avro.parser.domain
2+
3+
import amf.apicontract.internal.spec.avro.parser.context.AvroSchemaContext
4+
import amf.core.internal.datanode.DataNodeParser
5+
import amf.core.internal.metamodel.domain.ShapeModel
6+
import amf.core.internal.parser.YMapOps
7+
import amf.core.internal.parser.domain.Annotations
8+
import amf.shapes.client.scala.model.domain.AnyShape
9+
import amf.shapes.internal.domain.metamodel.AnyShapeModel
10+
import amf.shapes.internal.spec.common.parser.QuickFieldParserOps
11+
import org.yaml.model._
12+
13+
abstract class AvroComplexShapeParser(map: YMap)(implicit ctx: AvroSchemaContext)
14+
extends QuickFieldParserOps
15+
with AvroKeyExtractor {
16+
val shape: AnyShape
17+
18+
def parse(): AnyShape = {
19+
addTypeToCache()
20+
parseCommonFields()
21+
parseSpecificFields()
22+
parseDefault()
23+
shape
24+
}
25+
26+
def parseCommonFields(): Unit = {
27+
map.key("name", AnyShapeModel.Name in shape)
28+
map.key("namespace", (AnyShapeModel.AvroNamespace in shape).allowingAnnotations)
29+
map.key("aliases", (AnyShapeModel.Aliases in shape).allowingAnnotations)
30+
map.key("doc", (AnyShapeModel.Description in shape).allowingAnnotations)
31+
}
32+
33+
// each specific parser should override and parse it's specific fields
34+
def parseSpecificFields(): Unit
35+
36+
def parseDefault(): Unit = {
37+
map.key(
38+
"default",
39+
entry => {
40+
val dataNode = DataNodeParser(entry.value).parse()
41+
shape.set(ShapeModel.Default, dataNode, Annotations(entry))
42+
}
43+
)
44+
}
45+
46+
private def addTypeToCache(): Unit = {
47+
def getText(node: YNode) = node.as[YScalar].text
48+
def getAliases(entry: YMapEntry): IndexedSeq[String] = entry.value.as[YSequence].nodes.map(getText)
49+
val name = map.key("name").map(name => getText(name.value))
50+
val aliases = map.key("aliases").map(getAliases)
51+
name.foreach(ctx.globalSpace.put(_, shape))
52+
aliases.foreach(_.foreach(alias => ctx.globalSpace.put(alias, shape)))
53+
}
54+
}
55+
56+
trait AvroKeyExtractor {
57+
implicit class YMapKeys(map: YMap) {
58+
def typeValue: Option[YNode] = map.key("type").map(_.value)
59+
def `type`: Option[String] = typeValue.flatMap(_.asScalar).map(_.text)
60+
}
61+
62+
implicit class StringAvroOps(value: String) {
63+
def isPrimitive: Boolean =
64+
Seq("null", "boolean", "int", "long", "float", "double", "bytes", "string").contains(value)
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package amf.apicontract.internal.spec.avro.parser.domain
2+
3+
import amf.apicontract.internal.spec.avro.parser.context.AvroSchemaContext
4+
import amf.core.client.scala.model.DataType
5+
import amf.core.client.scala.model.domain.ScalarNode
6+
import amf.core.internal.parser.{YMapOps, YScalarYRead}
7+
import amf.shapes.client.scala.model.domain.AnyShape
8+
import org.yaml.model._
9+
10+
class AvroEnumParser(map: YMap)(implicit ctx: AvroSchemaContext) extends AvroTextTypeParser("string", Some(map)) {
11+
12+
override def parse(): AnyShape = {
13+
val shape = super.parse()
14+
parseCommonFields()
15+
parseSpecificFields()
16+
parseDefault()
17+
shape
18+
}
19+
20+
override def parseSpecificFields(): Unit = {
21+
map
22+
.key("symbols")
23+
.map(parseSymbols)
24+
.map(shape.withValues)
25+
}
26+
27+
private def parseSymbols(e: YMapEntry): Seq[ScalarNode] = {
28+
val symbols = e.value.as[YSequence]
29+
symbols.nodes.map(buildDataNode)
30+
}
31+
32+
private def buildDataNode(symbol: YNode) = ScalarNode(symbol.as[YScalar].text, Some(DataType.String), symbol)
33+
}

0 commit comments

Comments
 (0)