diff --git a/src/sbt-test/wasm/shopping-cart/build.sbt b/src/sbt-test/wasm/shopping-cart/build.sbt new file mode 100644 index 0000000..3548a6e --- /dev/null +++ b/src/sbt-test/wasm/shopping-cart/build.sbt @@ -0,0 +1,7 @@ +ThisBuild / version := "0.1" +ThisBuild / scalaVersion := "2.13.13" +ThisBuild / crossScalaVersions += "2.12.19" + +lazy val root = (project in file(".")) + .enablePlugins(WasmComponentPlugin) + .settings(wasmComponentPackageName := "example") diff --git a/src/sbt-test/wasm/shopping-cart/package.json b/src/sbt-test/wasm/shopping-cart/package.json new file mode 100644 index 0000000..cbd07d5 --- /dev/null +++ b/src/sbt-test/wasm/shopping-cart/package.json @@ -0,0 +1,10 @@ +{ + "scripts": { + "build": "jco componentize -w wit -o target/dist/main.wasm target/dist/main.js", + "componentize": "npm run build" + }, + "devDependencies": { + "@bytecodealliance/componentize-js": "0.10.2", + "@bytecodealliance/jco": "1.4.0" + } +} \ No newline at end of file diff --git a/src/sbt-test/wasm/shopping-cart/project/build.properties b/src/sbt-test/wasm/shopping-cart/project/build.properties new file mode 100644 index 0000000..4d5f78c --- /dev/null +++ b/src/sbt-test/wasm/shopping-cart/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.9.9 \ No newline at end of file diff --git a/src/sbt-test/wasm/shopping-cart/project/plugins.sbt b/src/sbt-test/wasm/shopping-cart/project/plugins.sbt new file mode 100644 index 0000000..e9b8f58 --- /dev/null +++ b/src/sbt-test/wasm/shopping-cart/project/plugins.sbt @@ -0,0 +1,7 @@ +sys.props.get("plugin.version") match { + case Some(version) => + addSbtPlugin("cloud.golem" % "sbt-wasm-component" % version) + case _ => + sys.error("""|The system property 'plugin.version' is not defined. + |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) +} diff --git a/src/sbt-test/wasm/shopping-cart/src/main/scala/example/ShoppingCart.scala b/src/sbt-test/wasm/shopping-cart/src/main/scala/example/ShoppingCart.scala new file mode 100644 index 0000000..02cd1bd --- /dev/null +++ b/src/sbt-test/wasm/shopping-cart/src/main/scala/example/ShoppingCart.scala @@ -0,0 +1,87 @@ +package example + +final case class State(userId: String, items: List[ProductItem]) { self => + def withUserId(userId: String): State = self.copy(userId = userId) + + def addItem(item: ProductItem): State = self.copy(items = self.items :+ item) + + def removeItem(productId: String): State = self.copy(items = self.items.filterNot(_.productId == productId)) + + def updateItemQuantity(productId: String, quantity: Integer): State = + self.copy(items = self.items.map { item => + if (item.productId == productId) ProductItem(item.productId, item.name, item.price, quantity) + else item + }) + + def clear: State = self.copy(items = List.empty) +} +object State { + val empty = State(userId = "", items = List.empty) +} + +@cloud.golem.WitExport +object ShoppingCart extends Api { self => + private var state = State.empty + + def initializeCart(userId: String): WitResult[String, String] = { + println(s"Initializing cart for user $userId") + if (math.random() > 0.1) { + state = state.withUserId(userId) + WitResult.ok(userId) + } else WitResult.err("Error while initializing cart") + } + + def addItem(item: ProductItem): Unit = { + println(s"Adding item to the cart of user ${state.userId}") + state = state.addItem(item) + } + + def removeItem(productId: String): Unit = { + println(s"Removing item with product ID $productId from the cart of user ${state.userId}") + state = state.removeItem(productId) + } + + def updateItemQuantity(productId: String, quantity: Integer): Unit = { + println(s"Updating quantity of item with product ID $productId to $quantity in the cart of user ${state.userId}") + + state = state.updateItemQuantity(productId, quantity) + } + + def checkout(): CheckoutResult = { + def reserveInventory(): Either[String, Unit] = + if (math.random() < 0.1) Left("Inventory not available") else Right(()) + + def chargeCreditCard(): Either[String, Unit] = Right(()) + + def generateOrder(): String = "238738674" + + def dispatchOrder(): Either[String, Unit] = Right(()) + + def clearState(): Unit = state = state.clear + + val result = + for { + _ <- reserveInventory() + _ <- chargeCreditCard() + orderId = generateOrder() + _ <- dispatchOrder() + _ = clearState() + _ = println(s"Checkout for order $orderId") + } yield OrderConfirmation(orderId) + + result match { + case Right(orderConfirmation) => CheckoutResult.success(orderConfirmation) + case Left(error) => CheckoutResult.error(error) + } + } + + def getCartContents(): WitList[ProductItem] = { + println(s"Getting cart contents for user ${state.userId}") + WitList.fromList(state.items) + } + + def getFirstItem(): WitOption[ProductItem] = { + println(s"Getting first item for user ${state.userId}") + WitOption.fromOption(state.items.headOption) + } +} \ No newline at end of file diff --git a/src/sbt-test/wasm/shopping-cart/test b/src/sbt-test/wasm/shopping-cart/test new file mode 100644 index 0000000..4143f91 --- /dev/null +++ b/src/sbt-test/wasm/shopping-cart/test @@ -0,0 +1,6 @@ +> +clean +$ exec cargo install golem-scalajs-wit-bindgen +> +wasmComponent +$ exists target/dist/main.js +$ exists target/dist/main.js.map +$ exists target/dist/main.wasm \ No newline at end of file diff --git a/src/sbt-test/wasm/shopping-cart/wit/example.wit b/src/sbt-test/wasm/shopping-cart/wit/example.wit new file mode 100644 index 0000000..d28d93b --- /dev/null +++ b/src/sbt-test/wasm/shopping-cart/wit/example.wit @@ -0,0 +1,37 @@ +package pack:name; + +interface api { + record product-item { + product-id: string, + name: string, + price: float32, + quantity: u32, + } + + record order-confirmation { + order-id: string, + } + + variant checkout-result { + error(string), + success(order-confirmation), + } + + initialize-cart: func(user-id: string) -> result; + + add-item: func(item: product-item) -> (); + + remove-item: func(product-id: string) -> (); + + update-item-quantity: func(product-id: string, quantity: u32) -> (); + + checkout: func() -> checkout-result; + + get-cart-contents: func() -> list; + + get-first-item: func() -> option; +} + +world main { + export api; +} \ No newline at end of file