From 93dec7846cdbdd5ef486c7bf4c07b4eee65502d5 Mon Sep 17 00:00:00 2001 From: Dima Date: Fri, 17 Sep 2021 11:21:04 +0300 Subject: [PATCH] Check service definition fields in TS and JS, fix functions and services count in output (#305) --- .../aqua/backend/js/JavaScriptFile.scala | 4 +++ .../aqua/backend/js/JavaScriptService.scala | 31 ++++++++++++------- .../aqua/backend/ts/TypeScriptFile.scala | 4 +++ .../aqua/backend/ts/TypeScriptService.scala | 7 +++++ cli/.jvm/src/test/scala/SourcesSpec.scala | 4 ++- .../scala/aqua/files/AquaFileSources.scala | 6 ++-- .../scala/aqua/compiler/AquaCompiled.scala | 2 +- .../scala/aqua/compiler/AquaCompiler.scala | 5 +-- 8 files changed, 44 insertions(+), 19 deletions(-) diff --git a/backend/js/src/main/scala/aqua/backend/js/JavaScriptFile.scala b/backend/js/src/main/scala/aqua/backend/js/JavaScriptFile.scala index ab1f1b57..0367ee75 100644 --- a/backend/js/src/main/scala/aqua/backend/js/JavaScriptFile.scala +++ b/backend/js/src/main/scala/aqua/backend/js/JavaScriptFile.scala @@ -9,6 +9,10 @@ case class JavaScriptFile(res: AquaRes) { def generate: String = s"""${Header} + | + |function missingFields(obj, fields) { + | return fields.filter(f => !(f in obj)) + |} | |// Services |${res.services.map(JavaScriptService(_)).map(_.generate).toList.mkString("\n\n")} diff --git a/backend/js/src/main/scala/aqua/backend/js/JavaScriptService.scala b/backend/js/src/main/scala/aqua/backend/js/JavaScriptService.scala index eba96a9c..6125d10a 100644 --- a/backend/js/src/main/scala/aqua/backend/js/JavaScriptService.scala +++ b/backend/js/src/main/scala/aqua/backend/js/JavaScriptService.scala @@ -34,8 +34,10 @@ case class JavaScriptService(srv: ServiceRes) { |}""".stripMargin ) + val membersNames = srv.members.map(_._1) + s""" - | export function ${registerName}(...args) { + |export function ${registerName}(...args) { | let peer; | let serviceId; | let service; @@ -50,7 +52,7 @@ case class JavaScriptService(srv: ServiceRes) { | } else if (typeof args[1] === 'string') { | serviceId = args[1]; | } ${defaultServiceIdBranch} - | + | | // Figuring out which overload is the service. | // If the first argument is not Fluence Peer and it is an object, then it can only be the service def | // If the first argument is peer, we are checking further. The second argument might either be @@ -64,16 +66,21 @@ case class JavaScriptService(srv: ServiceRes) { | service = args[2]; | } | - | peer.internals.callServiceHandler.use((req, resp, next) => { - | if (req.serviceId !== serviceId) { - | next(); - | return; - | } - | - | ${fnHandlers} - | - | next(); - | }); + | const incorrectServiceDefinitions = missingFields(service, [${membersNames.map { n => s"'$n'"}.mkString(", ")}]); + | if (!incorrectServiceDefinitions.length) { + | throw new Error("Error registering service ${srv.name}: missing functions: " + incorrectServiceDefinitions.map((d) => "'" + d + "'").join(", ")) + | } + | + | peer.internals.callServiceHandler.use((req, resp, next) => { + | if (req.serviceId !== serviceId) { + | next(); + | return; + | } + | + |${fnHandlers} + | + | next(); + | }); | } """.stripMargin } diff --git a/backend/ts/src/main/scala/aqua/backend/ts/TypeScriptFile.scala b/backend/ts/src/main/scala/aqua/backend/ts/TypeScriptFile.scala index c384f718..fa5894e5 100644 --- a/backend/ts/src/main/scala/aqua/backend/ts/TypeScriptFile.scala +++ b/backend/ts/src/main/scala/aqua/backend/ts/TypeScriptFile.scala @@ -9,6 +9,10 @@ case class TypeScriptFile(res: AquaRes) { def generate: String = s"""${Header} + | + |function missingFields(obj: any, fields: string[]): string[] { + | return fields.filter(f => !(f in obj)) + |} | |// Services |${res.services.map(TypeScriptService(_)).map(_.generate).toList.mkString("\n\n")} diff --git a/backend/ts/src/main/scala/aqua/backend/ts/TypeScriptService.scala b/backend/ts/src/main/scala/aqua/backend/ts/TypeScriptService.scala index 7b40c481..c7dcbff7 100644 --- a/backend/ts/src/main/scala/aqua/backend/ts/TypeScriptService.scala +++ b/backend/ts/src/main/scala/aqua/backend/ts/TypeScriptService.scala @@ -76,6 +76,8 @@ case class TypeScriptService(srv: ServiceRes) { | }""".stripMargin ) + val membersNames = srv.members.map(_._1) + s""" |export interface ${serviceTypeName} { | ${fnDefs} @@ -111,6 +113,11 @@ case class TypeScriptService(srv: ServiceRes) { | service = args[2]; | } | + | const incorrectServiceDefinitions = missingFields(service, [${membersNames.map { n => s"'$n'" }.mkString(", ")}]); + | if (!!incorrectServiceDefinitions.length) { + | throw new Error("Error registering service ${srv.name}: missing functions: " + incorrectServiceDefinitions.map((d) => "'" + d + "'").join(", ")) + | } + | | peer.internals.callServiceHandler.use((req, resp, next) => { | if (req.serviceId !== serviceId) { | next(); diff --git a/cli/.jvm/src/test/scala/SourcesSpec.scala b/cli/.jvm/src/test/scala/SourcesSpec.scala index bf144822..e4ccced4 100644 --- a/cli/.jvm/src/test/scala/SourcesSpec.scala +++ b/cli/.jvm/src/test/scala/SourcesSpec.scala @@ -128,7 +128,9 @@ class SourcesSpec extends AsyncFlatSpec with Matchers { content = "some random content" compiled = AquaCompiled[FileModuleId]( FileModuleId(filePath), - Seq(Generated("_hey.custom", content)) + Seq(Generated("_hey.custom", content)), + 1, + 1 ) resolved <- sourceGen.write(targetPath)(compiled) _ = { diff --git a/cli/src/main/scala/aqua/files/AquaFileSources.scala b/cli/src/main/scala/aqua/files/AquaFileSources.scala index 838b5c66..c565b9ba 100644 --- a/cli/src/main/scala/aqua/files/AquaFileSources.scala +++ b/cli/src/main/scala/aqua/files/AquaFileSources.scala @@ -108,13 +108,13 @@ class AquaFileSources[F[_]: AquaIO: Monad: Files: Functor]( } // Write content to a file and return a success message - private def writeWithResult(target: Path, content: String, size: Int) = { + private def writeWithResult(target: Path, content: String, funcsCount: Int, servicesCount: Int) = { filesIO .writeFile( target, content ) - .as(s"Result $target: compilation OK ($size functions)") + .as(s"Result $target: compilation OK ($funcsCount functions, $servicesCount services)") .value .map(Validated.fromEither) } @@ -138,7 +138,7 @@ class AquaFileSources[F[_]: AquaIO: Monad: Files: Functor]( result .leftMap(FileSystemError.apply) .map { target => - writeWithResult(target, compiled.content, ac.compiled.size) + writeWithResult(target, compiled.content, ac.funcsCount, ac.servicesCount) } .traverse(identity) } diff --git a/compiler/src/main/scala/aqua/compiler/AquaCompiled.scala b/compiler/src/main/scala/aqua/compiler/AquaCompiled.scala index e7a91690..3c8b4d1c 100644 --- a/compiler/src/main/scala/aqua/compiler/AquaCompiled.scala +++ b/compiler/src/main/scala/aqua/compiler/AquaCompiled.scala @@ -2,4 +2,4 @@ package aqua.compiler import aqua.backend.Generated -case class AquaCompiled[I](sourceId: I, compiled: Seq[Generated]) +case class AquaCompiled[I](sourceId: I, compiled: Seq[Generated], funcsCount: Int, servicesCount: Int) diff --git a/compiler/src/main/scala/aqua/compiler/AquaCompiler.scala b/compiler/src/main/scala/aqua/compiler/AquaCompiler.scala index b2404b9a..0aab6438 100644 --- a/compiler/src/main/scala/aqua/compiler/AquaCompiler.scala +++ b/compiler/src/main/scala/aqua/compiler/AquaCompiler.scala @@ -86,8 +86,9 @@ object AquaCompiler extends Logging { } .map( _.map { ap => - val compiled = backend.generate(AquaRes.fromContext(ap.context, config)) - AquaCompiled(ap.id, compiled) + val res = AquaRes.fromContext(ap.context, config) + val compiled = backend.generate(res) + AquaCompiled(ap.id, compiled, res.funcs.length.toInt, res.services.length.toInt) } ) }