mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 14:40:17 +00:00
Add errors to API results, fix AquaConfig, fix types (#620)
This commit is contained in:
parent
91169e2928
commit
269c68ad59
31
api/aqua-api-npm/aqua-api.d.ts
vendored
31
api/aqua-api-npm/aqua-api.d.ts
vendored
@ -2,6 +2,7 @@ import type {FunctionCallDef, ServiceDef} from "@fluencelabs/fluence/dist/intern
|
||||
|
||||
export class AquaConfig {
|
||||
constructor(logLevel: string, constants: string[], noXor: boolean, noRelay: boolean);
|
||||
|
||||
logLevel?: string
|
||||
constants?: string[]
|
||||
noXor?: boolean
|
||||
@ -14,14 +15,36 @@ export class AquaFunction {
|
||||
}
|
||||
|
||||
export class CompilationResult {
|
||||
services: ServiceDef[]
|
||||
services: Record<string, ServiceDef>
|
||||
functions: Record<string, AquaFunction>
|
||||
functionCall?: AquaFunction
|
||||
errors: string[]
|
||||
}
|
||||
|
||||
export class Input {
|
||||
constructor(input: string);
|
||||
|
||||
input: string
|
||||
}
|
||||
|
||||
export class Path {
|
||||
constructor(path: string);
|
||||
|
||||
path: string
|
||||
}
|
||||
|
||||
export class Call {
|
||||
constructor(functionCall: string,
|
||||
arguments: any,
|
||||
input: Input | Path);
|
||||
|
||||
functionCall: string
|
||||
arguments: any
|
||||
input: Input | Path
|
||||
}
|
||||
|
||||
export class Compiler {
|
||||
compileRun(functionStr: string, arguments: any, path: string, imports: string[], config?: AquaConfig): Promise<AquaFunction>;
|
||||
compile(path: string, imports: string[], config?: AquaConfig): Promise<CompilationResult>;
|
||||
compileString(input: string, imports: string[], config?: AquaConfig): Promise<CompilationResult>;
|
||||
compile(input: Input | Path | Call, imports: string[], config?: AquaConfig): Promise<CompilationResult>;
|
||||
}
|
||||
|
||||
export var Aqua: Compiler;
|
||||
|
@ -1,6 +1,7 @@
|
||||
package aqua.api
|
||||
|
||||
import aqua.ErrorRendering.showError
|
||||
import aqua.api.types.{AquaAPIConfig, AquaConfig, AquaFunction, CompilationResult, Input}
|
||||
import aqua.backend.{AirFunction, Backend, Generated}
|
||||
import aqua.compiler.*
|
||||
import aqua.files.{AquaFileSources, AquaFilesIO, FileModuleId}
|
||||
@ -18,7 +19,7 @@ import aqua.{AquaIO, SpanParser}
|
||||
import aqua.model.transform.{Transform, TransformConfig}
|
||||
import aqua.backend.api.APIBackend
|
||||
import cats.data.{Chain, NonEmptyChain, Validated, ValidatedNec}
|
||||
import cats.data.Validated.{invalidNec, validNec, Invalid, Valid}
|
||||
import cats.data.Validated.{Invalid, Valid, invalidNec, validNec}
|
||||
import cats.syntax.applicative.*
|
||||
import cats.syntax.apply.*
|
||||
import cats.syntax.flatMap.*
|
||||
@ -32,10 +33,11 @@ import scribe.Logging
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.Future
|
||||
import scala.scalajs.js.|
|
||||
import scala.scalajs.js
|
||||
import scala.scalajs.js.JSConverters.*
|
||||
import scala.scalajs.js.annotation.*
|
||||
import scala.scalajs.js.{undefined, UndefOr}
|
||||
import scala.scalajs.js.{UndefOr, undefined}
|
||||
import aqua.js.{FunctionDefJs, ServiceDefJs, VarJson}
|
||||
import aqua.model.AquaContext
|
||||
import aqua.raw.ops.CallArrowRawTag
|
||||
@ -43,53 +45,6 @@ import aqua.raw.value.{LiteralRaw, VarRaw}
|
||||
import aqua.res.AquaRes
|
||||
import cats.Applicative
|
||||
|
||||
@JSExportTopLevel("AquaFunction")
|
||||
case class AquaFunction(
|
||||
@JSExport
|
||||
funcDef: FunctionDefJs,
|
||||
@JSExport
|
||||
script: String
|
||||
)
|
||||
|
||||
case class AquaAPIConfig(
|
||||
logLevel: String = "info",
|
||||
constants: List[String] = Nil,
|
||||
noXor: Boolean = false,
|
||||
noRelay: Boolean = false
|
||||
)
|
||||
|
||||
object AquaAPIConfig {
|
||||
|
||||
def fromJS(cjs: AquaConfig): AquaAPIConfig = {
|
||||
AquaAPIConfig(
|
||||
cjs.logLevel.getOrElse("info"),
|
||||
cjs.constants.map(_.toList).getOrElse(Nil),
|
||||
cjs.noXor.getOrElse(false),
|
||||
cjs.noRelay.getOrElse(false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JSExportTopLevel("AquaConfig")
|
||||
case class AquaConfig(
|
||||
@JSExport
|
||||
logLevel: js.UndefOr[String],
|
||||
@JSExport
|
||||
constants: js.UndefOr[js.Array[String]],
|
||||
@JSExport
|
||||
noXor: js.UndefOr[Boolean],
|
||||
@JSExport
|
||||
noRelay: js.UndefOr[Boolean]
|
||||
)
|
||||
|
||||
@JSExportTopLevel("CompilationResult")
|
||||
case class CompilationResult(
|
||||
@JSExport
|
||||
services: js.Array[ServiceDefJs],
|
||||
@JSExport
|
||||
functions: js.Dictionary[AquaFunction]
|
||||
)
|
||||
|
||||
@JSExportTopLevel("Aqua")
|
||||
object AquaAPI extends App with Logging {
|
||||
|
||||
@ -102,86 +57,121 @@ object AquaAPI extends App with Logging {
|
||||
}
|
||||
|
||||
@JSExport
|
||||
def compileRun(
|
||||
def compile(
|
||||
input: types.Input | types.Path | types.Call,
|
||||
imports: js.Array[String],
|
||||
aquaConfigJS: js.UndefOr[AquaConfig]
|
||||
) = {
|
||||
val aquaConfig: AquaAPIConfig =
|
||||
aquaConfigJS.toOption.map(cjs => AquaAPIConfig.fromJS(cjs)).getOrElse(AquaAPIConfig())
|
||||
|
||||
val importsList = imports.toList
|
||||
|
||||
input match {
|
||||
case i: types.Input => compileString(i.input, importsList, aquaConfig)
|
||||
case p: types.Path => compilePath(p.path, importsList, aquaConfig)
|
||||
case c: types.Call =>
|
||||
val path = c.input match {
|
||||
case i: types.Input => i.input
|
||||
case p: types.Path => p.path
|
||||
}
|
||||
compileCall(c.functionCall, c.arguments, path, importsList, aquaConfig)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
def compileCall(
|
||||
functionStr: String,
|
||||
arguments: js.Dynamic,
|
||||
pathStr: String,
|
||||
imports: js.Array[String],
|
||||
aquaConfigJS: js.UndefOr[AquaConfig]
|
||||
): js.Promise[AquaFunction] = {
|
||||
imports: List[String],
|
||||
aquaConfig: AquaAPIConfig
|
||||
): js.Promise[CompilationResult] = {
|
||||
implicit val aio: AquaIO[IO] = new AquaFilesIO[IO]
|
||||
val aquaConfig: AquaAPIConfig =
|
||||
aquaConfigJS.toOption.map(cjs => AquaAPIConfig.fromJS(cjs)).getOrElse(AquaAPIConfig())
|
||||
LogFormatter.initLogger(Some(LogLevels.levelFromString(aquaConfig.logLevel).toOption.get))
|
||||
val transformConfig = TransformConfig()
|
||||
(
|
||||
LogLevels.levelFromString(aquaConfig.logLevel),
|
||||
Constants.parse(aquaConfig.constants)
|
||||
).mapN { (level, constants) =>
|
||||
|
||||
new FuncCompiler[IO](
|
||||
Some(RelativePath(Path(pathStr))),
|
||||
imports.toList.map(Path.apply),
|
||||
transformConfig
|
||||
).compile().map { contextV =>
|
||||
contextV.andThen { context =>
|
||||
CliFunc.fromString(functionStr).leftMap(errs => NonEmptyChain.fromNonEmptyList(errs)).andThen { cliFunc =>
|
||||
FuncCompiler.findFunction(context, cliFunc).andThen { arrow =>
|
||||
VarJson.checkDataGetServices(cliFunc.args, Some(arguments)).andThen {
|
||||
case (argsWithTypes, _) =>
|
||||
val func = cliFunc.copy(args = argsWithTypes)
|
||||
val preparer = new RunPreparer(
|
||||
func,
|
||||
arrow,
|
||||
transformConfig
|
||||
)
|
||||
preparer.prepare().map { ci =>
|
||||
AquaFunction(FunctionDefJs(ci.definitions), ci.air)
|
||||
val transformConfig = aquaConfig.getTransformConfig.copy(constants = constants)
|
||||
|
||||
LogFormatter.initLogger(Some(level))
|
||||
|
||||
new FuncCompiler[IO](
|
||||
Some(RelativePath(Path(pathStr))),
|
||||
imports.toList.map(Path.apply),
|
||||
transformConfig
|
||||
).compile()
|
||||
.map { contextV =>
|
||||
contextV.andThen { context =>
|
||||
CliFunc
|
||||
.fromString(functionStr)
|
||||
.leftMap(errs => NonEmptyChain.fromNonEmptyList(errs))
|
||||
.andThen { cliFunc =>
|
||||
FuncCompiler.findFunction(context, cliFunc).andThen { arrow =>
|
||||
VarJson.checkDataGetServices(cliFunc.args, Some(arguments)).andThen {
|
||||
case (argsWithTypes, _) =>
|
||||
val func = cliFunc.copy(args = argsWithTypes)
|
||||
val preparer = new RunPreparer(
|
||||
func,
|
||||
arrow,
|
||||
transformConfig
|
||||
)
|
||||
preparer.prepare().map { ci =>
|
||||
AquaFunction(FunctionDefJs(ci.definitions), ci.air)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.flatMap {
|
||||
case Valid(result) => IO.pure(result)
|
||||
case Invalid(err) =>
|
||||
err.map(_.show).distinct.map(OutputPrinter.errorF[IO]).sequence
|
||||
IO.raiseError[AquaFunction](new Error("Compilation failed."))
|
||||
}.unsafeToFuture().toJSPromise
|
||||
.flatMap {
|
||||
case Valid(result) => IO.pure(CompilationResult.result(js.Dictionary(), js.Dictionary(), Some(result)))
|
||||
case Invalid(err) =>
|
||||
val errs = err.map(_.show).distinct.toChain.toList
|
||||
IO.pure(CompilationResult.errs(errs))
|
||||
}
|
||||
.unsafeToFuture()
|
||||
.toJSPromise
|
||||
} match {
|
||||
case Valid(pr) => pr
|
||||
case Invalid(err) => js.Promise.resolve(CompilationResult.errs(err.toList))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JSExport
|
||||
def compile(
|
||||
def compilePath(
|
||||
pathStr: String,
|
||||
imports: js.Array[String],
|
||||
aquaConfigJS: js.UndefOr[AquaConfig]
|
||||
imports: List[String],
|
||||
aquaConfig: AquaAPIConfig
|
||||
): js.Promise[CompilationResult] = {
|
||||
implicit val aio: AquaIO[IO] = new AquaFilesIO[IO]
|
||||
val path = Path(pathStr)
|
||||
val sources = new AquaFileSources[IO](path, imports.toList.map(Path.apply))
|
||||
compileRaw(aquaConfigJS, sources)
|
||||
val sources = new AquaFileSources[IO](path, imports.map(Path.apply))
|
||||
compileRaw(aquaConfig, sources)
|
||||
}
|
||||
|
||||
@JSExport
|
||||
def compileString(
|
||||
input: String,
|
||||
imports: js.Array[String],
|
||||
aquaConfigJS: js.UndefOr[AquaConfig]
|
||||
imports: List[String],
|
||||
aquaConfig: AquaAPIConfig
|
||||
): js.Promise[CompilationResult] = {
|
||||
implicit val aio: AquaIO[IO] = new AquaFilesIO[IO]
|
||||
val path = Path("")
|
||||
|
||||
val strSources: AquaFileSources[IO] =
|
||||
new AquaFileSources[IO](path, imports.toList.map(Path.apply)) {
|
||||
new AquaFileSources[IO](path, imports.map(Path.apply)) {
|
||||
override def sources: IO[ValidatedNec[AquaFileError, Chain[(FileModuleId, String)]]] = {
|
||||
IO.pure(Valid(Chain.one((FileModuleId(path), input))))
|
||||
}
|
||||
}
|
||||
compileRaw(aquaConfigJS, strSources)
|
||||
compileRaw(aquaConfig, strSources)
|
||||
}
|
||||
|
||||
def compileRaw(
|
||||
aquaConfigJS: js.UndefOr[AquaConfig],
|
||||
aquaConfig: AquaAPIConfig,
|
||||
sources: AquaSources[IO, AquaFileError, FileModuleId]
|
||||
): js.Promise[CompilationResult] = {
|
||||
val aquaConfig =
|
||||
aquaConfigJS.toOption.map(cjs => AquaAPIConfig.fromJS(cjs)).getOrElse(AquaAPIConfig())
|
||||
|
||||
(
|
||||
LogLevels.levelFromString(aquaConfig.logLevel),
|
||||
@ -191,7 +181,7 @@ object AquaAPI extends App with Logging {
|
||||
LogFormatter.initLogger(Some(level))
|
||||
|
||||
val config = AquaCompilerConf(constants)
|
||||
val transformConfig = TransformConfig()
|
||||
val transformConfig = aquaConfig.getTransformConfig
|
||||
|
||||
val proc = for {
|
||||
res <- CompilerAPI
|
||||
@ -214,15 +204,21 @@ object AquaAPI extends App with Logging {
|
||||
jsResult <- res match {
|
||||
case Valid(compiled) =>
|
||||
val allGenerated: List[Generated] = compiled.toList.flatMap(_.compiled)
|
||||
val serviceDefs = allGenerated.flatMap(_.services).map(s => ServiceDefJs(s)).toJSArray
|
||||
val serviceDefs = allGenerated.flatMap(_.services).map(s => s.name -> ServiceDefJs(s))
|
||||
val functions = allGenerated.flatMap(
|
||||
_.air.map(as => (as.name, AquaFunction(FunctionDefJs(as.funcDef), as.air)))
|
||||
)
|
||||
|
||||
IO.pure(CompilationResult(serviceDefs, js.Dictionary.apply(functions: _*)))
|
||||
IO.pure(
|
||||
CompilationResult.result(
|
||||
js.Dictionary.apply(serviceDefs: _*),
|
||||
js.Dictionary.apply(functions: _*),
|
||||
None
|
||||
)
|
||||
)
|
||||
case Invalid(errChain) =>
|
||||
errChain.map(_.show).distinct.map(OutputPrinter.errorF[IO]).sequence
|
||||
IO.raiseError[CompilationResult](new Error("Compilation failed."))
|
||||
val errors = errChain.map(_.show).distinct.toChain.toList
|
||||
IO.pure[CompilationResult](CompilationResult.errs(errors))
|
||||
}
|
||||
} yield {
|
||||
jsResult
|
||||
@ -231,7 +227,7 @@ object AquaAPI extends App with Logging {
|
||||
proc.unsafeToFuture().toJSPromise
|
||||
} match {
|
||||
case Valid(pr) => pr
|
||||
case Invalid(err) => js.Promise.reject(err)
|
||||
case Invalid(err) => js.Promise.resolve(CompilationResult.errs(err.toList))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
103
api/aqua-api/src/main/scala/aqua/api/types/Types.scala
Normal file
103
api/aqua-api/src/main/scala/aqua/api/types/Types.scala
Normal file
@ -0,0 +1,103 @@
|
||||
package aqua.api.types
|
||||
|
||||
import aqua.api.*
|
||||
import aqua.js.{FunctionDefJs, ServiceDefJs}
|
||||
import aqua.model.transform.TransformConfig
|
||||
|
||||
import scala.scalajs.js
|
||||
import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel}
|
||||
import scala.scalajs.js.|
|
||||
import scala.scalajs.js.JSConverters.*
|
||||
|
||||
@JSExportTopLevel("AquaFunction")
|
||||
case class AquaFunction(
|
||||
@JSExport
|
||||
funcDef: FunctionDefJs,
|
||||
@JSExport
|
||||
script: String
|
||||
)
|
||||
|
||||
@JSExportTopLevel("Input")
|
||||
class Input(
|
||||
@JSExport
|
||||
val input: String
|
||||
)
|
||||
|
||||
@JSExportTopLevel("Path")
|
||||
class Path(
|
||||
@JSExport
|
||||
val path: String
|
||||
)
|
||||
|
||||
@JSExportTopLevel("Call")
|
||||
class Call(
|
||||
@JSExport
|
||||
val functionCall: String,
|
||||
@JSExport
|
||||
val arguments: js.Dynamic,
|
||||
@JSExport
|
||||
val input: Path | Input
|
||||
)
|
||||
|
||||
@JSExportTopLevel("AquaConfig")
|
||||
class AquaConfig(
|
||||
@JSExport
|
||||
val logLevel: js.UndefOr[String],
|
||||
@JSExport
|
||||
val constants: js.UndefOr[js.Array[String]],
|
||||
@JSExport
|
||||
val noXor: js.UndefOr[Boolean],
|
||||
@JSExport
|
||||
val noRelay: js.UndefOr[Boolean]
|
||||
)
|
||||
|
||||
@JSExportTopLevel("CompilationResult")
|
||||
class CompilationResult(
|
||||
@JSExport
|
||||
val services: js.Dictionary[ServiceDefJs],
|
||||
@JSExport
|
||||
val functions: js.Dictionary[AquaFunction],
|
||||
@JSExport
|
||||
val functionCall: js.UndefOr[AquaFunction],
|
||||
@JSExport
|
||||
val errors: js.Array[String]
|
||||
)
|
||||
|
||||
object CompilationResult {
|
||||
|
||||
def result(
|
||||
services: js.Dictionary[ServiceDefJs],
|
||||
functions: js.Dictionary[AquaFunction],
|
||||
call: Option[AquaFunction]
|
||||
): CompilationResult =
|
||||
new CompilationResult(services, functions, call.orNull, js.Array())
|
||||
|
||||
def errs(
|
||||
errors: List[String]
|
||||
): CompilationResult =
|
||||
CompilationResult(js.Dictionary(), js.Dictionary(), null, errors.toJSArray)
|
||||
}
|
||||
|
||||
case class AquaAPIConfig(
|
||||
logLevel: String = "info",
|
||||
constants: List[String] = Nil,
|
||||
noXor: Boolean = false,
|
||||
noRelay: Boolean = false
|
||||
) {
|
||||
|
||||
def getTransformConfig: TransformConfig =
|
||||
if (noRelay) TransformConfig(relayVarName = None, wrapWithXor = !noXor)
|
||||
else TransformConfig(wrapWithXor = !noXor)
|
||||
}
|
||||
|
||||
object AquaAPIConfig {
|
||||
|
||||
def fromJS(cjs: AquaConfig): AquaAPIConfig = {
|
||||
AquaAPIConfig(
|
||||
cjs.logLevel.getOrElse("info"),
|
||||
cjs.constants.map(_.toList).getOrElse(Nil),
|
||||
cjs.noXor.getOrElse(false),
|
||||
cjs.noRelay.getOrElse(false)
|
||||
)
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ object APIBackend extends Backend {
|
||||
srv.members.map { case (n, a) => (n, ArrowTypeDef(a)) }
|
||||
)
|
||||
|
||||
ServiceDef(srv.defaultId.map(s => s.replace("\"", "")), functions)
|
||||
ServiceDef(srv.defaultId.map(s => s.replace("\"", "")), functions, srv.name)
|
||||
}.toList
|
||||
|
||||
Generated("", "", airGenerated.flatMap(_.air).toList, services) :: Nil
|
||||
|
@ -68,7 +68,7 @@ object TypeDefinition {
|
||||
)
|
||||
}
|
||||
|
||||
implicit val encodeServiceDefType: Encoder[ServiceDef] = { case ServiceDef(sId, functions) =>
|
||||
implicit val encodeServiceDefType: Encoder[ServiceDef] = { case ServiceDef(sId, functions, name) =>
|
||||
Json.obj(
|
||||
("defaultServiceId", sId.asJson),
|
||||
("functions", encodeProdDefType(functions))
|
||||
@ -195,7 +195,7 @@ case class NamesConfig(
|
||||
)
|
||||
|
||||
// Describes service
|
||||
case class ServiceDef(defaultServiceId: Option[String], functions: LabeledProductTypeDef)
|
||||
case class ServiceDef(defaultServiceId: Option[String], functions: LabeledProductTypeDef, name: String)
|
||||
|
||||
// Describes top-level function
|
||||
case class FunctionDef(
|
||||
|
@ -22,7 +22,7 @@ case class OutputService(srv: ServiceRes, types: Types) {
|
||||
srv.members.map { case (n, a) => (n, ArrowTypeDef(a)) }
|
||||
)
|
||||
|
||||
val serviceDef = ServiceDef(srv.defaultId.map(s => s.replace("\"", "")), functions)
|
||||
val serviceDef = ServiceDef(srv.defaultId.map(s => s.replace("\"", "")), functions, srv.name)
|
||||
|
||||
s"""
|
||||
|${serviceTypes.generate}
|
||||
|
@ -17,7 +17,7 @@ val scribeV = "3.7.1"
|
||||
name := "aqua-hll"
|
||||
|
||||
val commons = Seq(
|
||||
baseAquaVersion := "0.9.0",
|
||||
baseAquaVersion := "0.9.1",
|
||||
version := baseAquaVersion.value + "-" + sys.env.getOrElse("BUILD_NUMBER", "SNAPSHOT"),
|
||||
scalaVersion := dottyVersion,
|
||||
libraryDependencies ++= Seq(
|
||||
|
@ -27,7 +27,8 @@ class Service(serviceId: String, functions: NonEmptyList[AquaFunction]) extends
|
||||
handlers.toList,
|
||||
ServiceDef(
|
||||
None,
|
||||
defs
|
||||
defs,
|
||||
""
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ case class Plugin(name: String, functions: List[Function]) {
|
||||
peer,
|
||||
name,
|
||||
handlers,
|
||||
ServiceDef(Some(name), LabeledProductTypeDef(funcTypes))
|
||||
ServiceDef(Some(name), LabeledProductTypeDef(funcTypes), "")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user