Need help with jscala?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

nau
199 Stars 24 Forks MIT License 127 Commits 6 Opened issues

Description

Scala macro that produces JavaScript from Scala code.

Services available

!
?

Need anything else?

Contributors list

JScala

Scala macro that produces JavaScript from Scala code. Let it be type safe!

Build Status

Gitter

Supported Features:

  • Variable definitions, basic unary and binary operations
  • Named and anonymous functions
  • Scala Arrays/Seq as JavaScript Array literals
  • Scala Map and anonymous classes as JavaScript object
  • if, while, for..in and for statements
  • Scala if as an expression (e.g. val a = if (true) 1 else 2)
  • Scala match as JavaScript switch
  • Basic Scala class/trait definition to JavaScript object definition translation
  • Global JavaScript functions (parseInt etc)
  • Basic Browser objects (window, history, location etc)
  • Basic HTML DOM objects (Document, Element, Attribute, Node, NodeList etc)
  • Raw JavaScript inclusion
  • Values and function call injections from your Scala code
  • Generated JavaScript eval using Java ScriptEngine
  • Pretty printing and compression using YUI compressor
  • Basic @Javascript macro annotation support
  • Basic toJson/fromJson macros
  • @Typescripted annotation

Examples

This Scala code has no meaning but shows basic ideas:

val replacement = "text"
val js = javascript {
  window.setTimeout(() => {
    val r = new RegExp("d.*", "g")
    class Point(val x: Int, val y: Int)
    val point = new Point(1, 2)
    def func(i: String) = r.exec(i)
    val list = document.getElementById("myList2")
    val map = collection.mutable.Map[String, String]()
    if (typeof(map) == "string") {
      for (idx 

It will print

window.setTimeout(function () {
    var r = new RegExp("d.*", "g");
    function Point(x, y) {
      this.x = x;
      this.y = y;
    };
    var point = new Point(1, 2);
    function func(i) {
      return r.exec(i);
    };
    var list = document.getElementById("myList2");
    var map = {};
    if (typeof(map) == "string") for (var idx = 0; idx < list.attributes.length; ++idx) {
      var attr = list.attributes.item(idx);
      map[attr.name] = func(attr.textContent);
    } else {
      var obj = {
        field: 1,
        func2: function (i) {
          return "string";
        }
      };
      var links = ["https://github.com/nau/scala"];
      for (var linkIdx = 0, link = links[linkIdx]; linkIdx < links.length; link = links[++linkIdx]) {
        var raw = 'JavaScript';
        console.log((link + obj.func2(obj.field)) + point.x);
      };
      window.location.href = links[0].replace("scala", "jscala");
    };
  }, 1000)

How To Use

In your build.sbt add

scalaVersion := "2.13.2"

libraryDependencies += "org.jscala" %% "jscala-macros" % "0.5"

If you want to try the latest snapshot:

scalaVersion := "2.13.2"

resolvers += Resolver.sonatypeRepo("snapshots")

libraryDependencies += "org.jscala" %% "jscala-macros" % "0.6-SNAPSHOT"

In your code

import org.jscala._
val js = javascript { ... }
println(js.asString)
println(js.compress)
println(js.eval())

That's it!

How To Try Macro Annotations

In your build.sbt add

scalaVersion := "2.13.2"

libraryDependencies += "org.jscala" %% "jscala-macros" % "0.5"

libraryDependencies += "org.jscala" %% "jscala-annots" % "0.5"

In your code

import org.jscala._
@Javascript class User(val name: String, val id: Int)
@Javascript(json = false) class Greeter {
  def hello(u: User) {
    print("Hello, " + u.name + "\n")
  }
}
// Run on JVM
val u1 = new User("Alex", 1)
val greeter = new Greeter()
greeter.hello(u1) // prints "Hello, Alex"
val json = u1.js.json.asString
val main = javascript {
    val u = new User("nau", 2)
    val u1Json = eval("(" + inject(json) + ")").as[User] // read User from json string generated above
    val t = new Greeter()
    t.hello(u)
    t.hello(u1Json)
  }
val js = User.jscala.javascript ++ Greeter.jscala.javascript ++ main // join classes definitions with main code
js.eval() // run using Rhino
println(js.asString) // prints resulting JavaScript

Run it and you'll get

Hello, Alex

Hello, nau Hello, Alex { function User(name, id) { this.name = name; this.id = id; }; function Greeter() { this.hello = function (u) { print(("Hello, " + u.name) + "\n"); }; }; var u = new User("nau", 2); var u1Json = eval(("(" + "{\n "name": "Alex",\n "id": 1\n}") + ")"); var t = new Greeter(); t.hello(u); t.hello(u1Json); }

See AES example:

https://github.com/nau/jscala/blob/master/jscala-examples/src/main/scala/org/jscalaexample/AES.scala

It's AES Scala implementation which is used for both Scala and JavaScript encryption/decryption.

How To Build And Play Some Tetris

Make sure you have at least -Xmx750Mb for your sbt. Don't know why but it takes up to 700Mb to compile jscala-macros project.

In sbt shell run

tetris
task. It will compile and generate tetris.js file in jscala-examples/javascript-tetris and open Tetris game in your browser. Tetris is fully written in Scala and translates to JavaScript mostly literally.

Tetris sources are here: jscala-examples/src/main/scala/org/jscalaexample/Tetris.scala

Planned Features

  • Language support improvements
  • Web frameworks support: Play, Lift

Feedback

Any feedback is very welcome!

You can use JScala mailing list if you have any questions.

Or simply ask me on Twitter: @atlanter

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.