Skip to content

Commit

Permalink
Merge pull request #1932 from aml-org/publish-5.4.8
Browse files Browse the repository at this point in the history
W-13925199 Publish 5.4.8
  • Loading branch information
damianpedra authored Feb 9, 2024
2 parents 58ae924 + 7140bff commit 25fd0ed
Show file tree
Hide file tree
Showing 330 changed files with 19,477 additions and 1,556 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
package amf.apicontract.internal.spec.async

import amf.apicontract.internal.spec.async.AsyncHeader.Async20Header
import amf.apicontract.internal.spec.async.parser.context.{Async20WebApiContext, AsyncWebApiContext}
import amf.apicontract.internal.spec.async.AsyncHeader.{
Async20Header,
Async21Header,
Async22Header,
Async23Header,
Async24Header,
Async25Header,
Async26Header
}
import amf.apicontract.internal.spec.async.parser.context.{Async2WebApiContext, AsyncWebApiContext}
import amf.apicontract.internal.spec.async.parser.document
import amf.apicontract.internal.spec.async.parser.domain.declarations.{
Async20DeclarationParser,
Async23DeclarationParser,
Async24DeclarationParser
}
import amf.apicontract.internal.spec.common.AsyncWebApiDeclarations
import amf.apicontract.internal.spec.oas.OasLikeParsePlugin
import amf.apicontract.internal.spec.raml.Raml10ParsePlugin
Expand All @@ -17,24 +30,29 @@ object Async20ParsePlugin extends OasLikeParsePlugin {

override def spec: Spec = AsyncApi20

override def applies(element: Root): Boolean = AsyncHeader(element).contains(Async20Header)
override def applies(element: Root): Boolean = AsyncHeader(element).isDefined

override def validSpecsToReference: Seq[Spec] =
super.validSpecsToReference :+ Raml10ParsePlugin.spec

override def mediaTypes: Seq[String] = Seq(Mimes.`application/yaml`, Mimes.`application/json`)

override def parse(document: Root, ctx: ParserContext): BaseUnit = {
implicit val newCtx: AsyncWebApiContext = context(document.location, document.references, ctx.parsingOptions, ctx)
val header = parseHeader(document)
implicit val newCtx: AsyncWebApiContext =
context(document.location, document.references, ctx.parsingOptions, ctx, spec = header.spec)
restrictCrossSpecReferences(document, ctx)
val parsed = parseAsyncUnit(document)
val parsed = parseAsyncUnit(header, document)
promoteFragments(parsed, newCtx)
}

private def parseAsyncUnit(root: Root)(implicit ctx: AsyncWebApiContext): BaseUnit = {
AsyncHeader(root) match {
case Some(Async20Header) => document.AsyncApi20DocumentParser(root).parseDocument()
case _ => // unreachable as it is covered in canParse()
private def parseHeader(root: Root): AsyncHeader =
AsyncHeader(root).getOrElse(throw new InvalidDocumentHeaderException(spec.id))

private def parseAsyncUnit(header: AsyncHeader, root: Root)(implicit ctx: AsyncWebApiContext): BaseUnit = {
header match {
case Async20Header => document.AsyncApi20DocumentParser(root).parseDocument()
case _ =>
throw new InvalidDocumentHeaderException(spec.id)
}
}
Expand All @@ -44,11 +62,12 @@ object Async20ParsePlugin extends OasLikeParsePlugin {
refs: Seq[ParsedReference],
options: ParsingOptions,
wrapped: ParserContext,
ds: Option[AsyncWebApiDeclarations] = None
): Async20WebApiContext = {
ds: Option[AsyncWebApiDeclarations] = None,
spec: Spec
): Async2WebApiContext = {
// ensure unresolved references in external fragments are not resolved with main api definitions
val cleanContext = wrapped.copy(futureDeclarations = EmptyFutureDeclarations())
cleanContext.globalSpace = wrapped.globalSpace
new Async20WebApiContext(loc, refs, cleanContext, ds, options = options)
Async2WebApiContext(loc, refs, cleanContext, ds, options, spec)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,34 @@ package amf.apicontract.internal.spec.async

import amf.core.client.scala.parse.document.SyamlParsedDocument
import amf.core.internal.parser.{Root, YMapOps, YNodeLikeOps}
import amf.core.internal.remote.{
AsyncApi20,
AsyncApi21,
AsyncApi22,
AsyncApi23,
AsyncApi24,
AsyncApi25,
AsyncApi26,
Spec
}
import org.yaml.model.YMap

/** */
class AsyncHeader(val key: String, val value: String) {
sealed case class AsyncHeader private (key: String, value: String, spec: Spec) {
def tuple: (String, String) = (key, value)
}

object AsyncHeader {

val async = "asyncapi"

object Async20Header extends AsyncHeader(async, "2.0.0")
object Async20Header extends AsyncHeader(async, "2.0.0", AsyncApi20)
object Async21Header extends AsyncHeader(async, "2.1.0", AsyncApi21)
object Async22Header extends AsyncHeader(async, "2.2.0", AsyncApi22)
object Async23Header extends AsyncHeader(async, "2.3.0", AsyncApi23)
object Async24Header extends AsyncHeader(async, "2.4.0", AsyncApi24)
object Async25Header extends AsyncHeader(async, "2.5.0", AsyncApi25)
object Async26Header extends AsyncHeader(async, "2.6.0", AsyncApi26)

def apply(root: Root): Option[AsyncHeader] =
root.parsed match {
Expand All @@ -31,6 +47,12 @@ object AsyncHeader {
def apply(text: String): Option[AsyncHeader] = {
text match {
case Async20Header.value => Some(Async20Header)
case Async21Header.value => Some(Async21Header)
case Async22Header.value => Some(Async22Header)
case Async23Header.value => Some(Async23Header)
case Async24Header.value => Some(Async24Header)
case Async25Header.value => Some(Async25Header)
case Async26Header.value => Some(Async26Header)
case _ => None
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package amf.apicontract.internal.spec.async

import amf.apicontract.internal.spec.async.AsyncHeader._
import amf.apicontract.internal.spec.async.parser.context.{Async2WebApiContext, AsyncWebApiContext}
import amf.apicontract.internal.spec.async.parser.document
import amf.apicontract.internal.spec.common.AsyncWebApiDeclarations
import amf.apicontract.internal.spec.oas.OasLikeParsePlugin
import amf.apicontract.internal.spec.raml.Raml10ParsePlugin
import amf.core.client.scala.config.ParsingOptions
import amf.core.client.scala.exception.InvalidDocumentHeaderException
import amf.core.client.scala.model.document.BaseUnit
import amf.core.client.scala.parse.document.{EmptyFutureDeclarations, ParsedReference, ParserContext}
import amf.core.internal.parser.Root
import amf.core.internal.remote.{AsyncApi20, Mimes, Spec}

/*
* This plugin should be merged with Async20ParsePlugin after Async 2.x feature is finished
*/
object NotFinishedAsync20ParsePlugin extends OasLikeParsePlugin {

override def spec: Spec = AsyncApi20

override def applies(element: Root): Boolean = AsyncHeader(element).isDefined

override def validSpecsToReference: Seq[Spec] =
super.validSpecsToReference :+ Raml10ParsePlugin.spec

override def mediaTypes: Seq[String] = Seq(Mimes.`application/yaml`, Mimes.`application/json`)

override def parse(document: Root, ctx: ParserContext): BaseUnit = {
val header = parseHeader(document)
implicit val newCtx: AsyncWebApiContext =
context(document.location, document.references, ctx.parsingOptions, ctx, spec = header.spec)
restrictCrossSpecReferences(document, ctx)
val parsed = parseAsyncUnit(header, document)
promoteFragments(parsed, newCtx)
}

private def parseHeader(root: Root): AsyncHeader =
AsyncHeader(root).getOrElse(throw new InvalidDocumentHeaderException(spec.id))

private def parseAsyncUnit(header: AsyncHeader, root: Root)(implicit ctx: AsyncWebApiContext): BaseUnit = {
header match {
case Async20Header => document.AsyncApi20DocumentParser(root).parseDocument()
case Async21Header => document.AsyncApi21DocumentParser(root).parseDocument()
case Async22Header => document.AsyncApi22DocumentParser(root).parseDocument()
case Async23Header => document.AsyncApi23DocumentParser(root).parseDocument()
case Async24Header => document.AsyncApi24DocumentParser(root).parseDocument()
case Async25Header => document.AsyncApi25DocumentParser(root).parseDocument()
case Async26Header => document.AsyncApi26DocumentParser(root).parseDocument()
case _ =>
throw new InvalidDocumentHeaderException(spec.id)
}
}

private def context(
loc: String,
refs: Seq[ParsedReference],
options: ParsingOptions,
wrapped: ParserContext,
ds: Option[AsyncWebApiDeclarations] = None,
spec: Spec
): Async2WebApiContext = {
// ensure unresolved references in external fragments are not resolved with main api definitions
val cleanContext = wrapped.copy(futureDeclarations = EmptyFutureDeclarations())
cleanContext.globalSpace = wrapped.globalSpace
Async2WebApiContext(loc, refs, cleanContext, ds, options, spec)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,24 @@ import amf.apicontract.client.scala.model.domain.Tag
import amf.apicontract.client.scala.model.domain.api.{Api, WebApi}
import amf.apicontract.internal.metamodel.domain.api.WebApiModel
import amf.apicontract.internal.spec.async.emitters.context.AsyncSpecEmitterContext
import amf.apicontract.internal.spec.async.emitters.domain.{AsyncApiCreativeWorksEmitter, AsyncApiEndpointsEmitter, AsyncApiServersEmitter}
import amf.apicontract.internal.spec.async.emitters.domain.{AsyncApiCreativeWorksEmitter, AsyncApiEndpointsEmitter, AsyncApiServersEmitter, DefaultContentTypeEmitter}
import amf.apicontract.internal.spec.common.emitter
import amf.apicontract.internal.spec.common.emitter.{AgnosticShapeEmitterContextAdapter, SecurityRequirementsEmitter}
import amf.apicontract.internal.spec.oas.emitter.domain.{InfoEmitter, TagsEmitter}
import amf.core.client.scala.model.document.{BaseUnit, Document}
import amf.core.client.scala.model.domain.{AmfArray, AmfScalar}
import amf.core.internal.parser.domain.FieldEntry
import amf.core.internal.remote.{AsyncApi20, Spec}
import amf.core.internal.render.BaseEmitters.{EmptyMapEmitter, EntryPartEmitter, ValueEmitter, traverse}
import amf.core.internal.remote.{AsyncApi20, AsyncApi21, AsyncApi22, AsyncApi23, AsyncApi24, AsyncApi25, AsyncApi26, Spec}
import amf.core.internal.render.BaseEmitters.{EmptyMapEmitter, EntryPartEmitter, ValueEmitter, pos, traverse}
import amf.core.internal.render.SpecOrdering
import amf.core.internal.render.emitters.EntryEmitter
import amf.core.internal.validation.CoreValidations.TransformationValidation
import amf.core.internal.validation.CoreValidations.{NotLinkable, TransformationValidation}
import amf.shapes.client.scala.model.domain.CreativeWork
import amf.shapes.internal.annotations.OrphanOasExtension
import amf.shapes.internal.spec.common.emitter.annotations.AnnotationsEmitter
import org.mulesoft.common.client.lexical.Position
import org.yaml.model.{YDocument, YNode, YScalar, YType}

import scala.collection.mutable

class AsyncApi20DocumentEmitter(document: BaseUnit)(implicit val specCtx: AsyncSpecEmitterContext) {
Expand Down Expand Up @@ -71,8 +74,23 @@ class AsyncApi20DocumentEmitter(document: BaseUnit)(implicit val specCtx: AsyncS
def wrapDeclarations(emitters: Seq[EntryEmitter], ordering: SpecOrdering): Seq[EntryEmitter] =
Seq(emitter.DeclarationsEmitterWrapper(emitters, ordering))

def versionEntry(b: YDocument.EntryBuilder): Unit =
b.asyncapi = YNode(YScalar("2.0.0"), YType.Str) // this should not be necessary but for use the same logic
def versionEntry(b: YDocument.EntryBuilder): Unit = {
val default = "2.6.0" // the default is the latest version to always emit a valid Async Api spec
val versionToEmit = document.sourceSpec
.map {
case AsyncApi20 => "2.0.0"
case AsyncApi21 => "2.1.0"
case AsyncApi22 => "2.2.0"
case AsyncApi23 => "2.3.0"
case AsyncApi24 => "2.4.0"
case AsyncApi25 => "2.5.0"
case AsyncApi26 => "2.6.0"
case _ => default
}
.getOrElse(default)

b.asyncapi = YNode(YScalar(versionToEmit), YType.Str) // this should not be necessary but for use the same logic
}

case class WebApiEmitter(api: Api, ordering: SpecOrdering, spec: Option[Spec], references: Seq[BaseUnit]) {
val emitters: Seq[EntryEmitter] = {
Expand Down Expand Up @@ -105,6 +123,8 @@ class AsyncApi20DocumentEmitter(document: BaseUnit)(implicit val specCtx: AsyncS

fs.entry(WebApiModel.Security).map(f => result += SecurityRequirementsEmitter("security", f, ordering))

fs.entry(WebApiModel.ContentType).map(f => result += DefaultContentTypeEmitter(f, ordering))

result ++= AnnotationsEmitter(api, ordering).emitters
ordering.sorted(result)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package amf.apicontract.internal.spec.async.emitters.domain

import amf.core.client.scala.model.domain.{AmfArray, AmfScalar}
import amf.core.internal.parser.domain.FieldEntry
import amf.core.internal.render.BaseEmitters.pos
import amf.core.internal.render.SpecOrdering
import amf.core.internal.render.emitters.EntryEmitter
import org.mulesoft.common.client.lexical.Position
import org.yaml.model.{YDocument, YNode}

case class DefaultContentTypeEmitter(f: FieldEntry, ordering: SpecOrdering) extends EntryEmitter {
override def emit(b: YDocument.EntryBuilder): Unit = {
val maybeString: Option[String] = getValue
maybeString.foreach(contentType => b.entry("defaultContentType", YNode(contentType)))

}

private def getValue: Option[String] = {
f.value.value match {
case array: AmfArray =>
array.values
.headOption
.map(f => f.asInstanceOf[AmfScalar].value.toString)
case _ =>
None
}
}

override def position(): Position = pos(f.value.annotations)
}
Loading

0 comments on commit 25fd0ed

Please sign in to comment.