Skip to content

Commit f2bb6ac

Browse files
committed
Announcing Scala.js 0.6.14.
1 parent 2558f4c commit f2bb6ac

File tree

9 files changed

+273
-14
lines changed

9 files changed

+273
-14
lines changed

_config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,6 @@ colors: #in hex code if not noted else
5757

5858
### VERSIONS ###
5959
versions:
60-
scalaJS: 0.6.13
60+
scalaJS: 0.6.14
6161
scalaJSBinary: 0.6
6262
scalaJSDOM: 0.9.1

_data/library/versions.yml

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
- 0.6.0
2-
- 0.6.1
3-
- 0.6.2
4-
- 0.6.3
5-
- 0.6.4
6-
- 0.6.5
7-
- 0.6.6
8-
- 0.6.8
9-
- 0.6.13
1+
- 0.6.0
2+
- 0.6.1
3+
- 0.6.2
4+
- 0.6.3
5+
- 0.6.4
6+
- 0.6.5
7+
- 0.6.6
8+
- 0.6.8
9+
- 0.6.13
10+
- 0.6.14
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
---
2+
layout: post
3+
title: Announcing Scala.js 0.6.14
4+
category: news
5+
tags: [releases]
6+
permalink: /news/2016/12/21/announcing-scalajs-0.6.14/
7+
---
8+
9+
10+
We are excited to announce the release of Scala.js 0.6.14!
11+
12+
This release features a few language enhancements for interoperability.
13+
Among others, it allows to export top-level functions, and provides language support for JavaScript "configuration objects".
14+
15+
<!--more-->
16+
17+
## Getting started
18+
19+
If you are new to Scala.js, head over to
20+
[the tutorial]({{ BASE_PATH }}/tutorial/).
21+
22+
## Release notes
23+
24+
If upgrading from Scala.js 0.6.12 or earlier, make sure to read [the release notes of 0.6.13]({{ BASE_PATH }}/news/2016/10/17/announcing-scalajs-0.6.13/), which contain some breaking changes in sbt build definitions.
25+
26+
As a minor release, 0.6.14 is backward source and binary compatible with previous releases in the 0.6.x series.
27+
Libraries compiled with earlier versions can be used with 0.6.14 without change.
28+
However, it is not forward compatible: libraries compiled with 0.6.14 cannot be used by projects using 0.6.{0-13}.
29+
30+
Please report any issues [on GitHub](https://github.com/scala-js/scala-js/issues).
31+
32+
## JavaScript configuration objects
33+
34+
Many JavaScript libraries expose APIs where options are given in what we call configuration objects.
35+
A well-known example would be the [`$.ajax()`](http://api.jquery.com/jquery.ajax/) function of jQuery, which we can declare as:
36+
37+
{% highlight scala %}
38+
@ScalaJSDefined
39+
trait JQueryAjaxSettings extends js.Object {
40+
val data: js.Object | String | js.Array[Any]
41+
val contentType: Boolean | String
42+
val crossDomain: Boolean
43+
val success: js.Function3[Any, String, JQueryXHR, _]
44+
...
45+
}
46+
47+
def ajax(url: String, settings: JQueryAjaxSettings): JQueryXHR = js.native
48+
{% endhighlight %}
49+
50+
The `val`s need to be declared abstract because, in previous versions of Scala.js, `@ScalaJSDefined` traits could not have concrete members.
51+
This makes it tedious to create an instance of `JQueryAjaxSettings`, since the Scala type system forces us to fill them in, although the fields are optional in JavaScript.
52+
Previous workarounds include a) using `js.Dynamic.literal(...).asInstanceOf[JQueryAjaxSettings]` or b) using [`JSOptionBuilder`](https://github.com/jducoeur/jsext#jsoptionbuilder).
53+
54+
Scala.js 0.6.14 finally provides language support for this kind of API.
55+
It is now allowed to have concrete members in `@ScalaJSDefined` traits, *if* their right-hand-side is `= js.undefined` (this implies that their type must be a supertype of `js.UndefOr[Nothing]`).
56+
With this relaxed rule, we can define `JQueryAjaxSettings` as follows:
57+
58+
{% highlight scala %}
59+
@ScalaJSDefined
60+
trait JQueryAjaxSettings extends js.Object {
61+
val data: js.UndefOr[js.Object | String | js.Array[Any]] = js.undefined
62+
val contentType: js.UndefOr[Boolean | String] = js.undefined
63+
val crossDomain: js.UndefOr[Boolean] = js.undefined
64+
val success: js.UndefOr[js.Function3[Any, String, JQueryXHR, _]] = js.undefined
65+
...
66+
}
67+
{% endhighlight %}
68+
69+
When calling `ajax()`, we can now give an anonymous object that overrides only the `val`s we care about:
70+
71+
{% highlight scala %}
72+
jQuery.ajax(someURL, new JQueryAjaxSettings {
73+
override val crossDomain: js.UndefOr[Boolean] = true
74+
override val success: js.UndefOr[js.Function3[Any, String, JQueryXHR, _]] = {
75+
js.defined { (data: Any, textStatus: String, xhr: JQueryXHR) =>
76+
println("Status: " + textStatus)
77+
}
78+
}
79+
})
80+
{% endhighlight %}
81+
82+
Note that for functions, we use `js.defined { ... }` to drive Scala's type inference.
83+
Otherwise, it needs to apply two implicit conversions, which is not allowed.
84+
85+
The explicit types are still quite annoying, but they are only necessary in Scala 2.10 and 2.11.
86+
If you use Scala 2.12, you can omit all the type annotations (but keep `js.defined`), thanks to improved type inference for `val`s and SAM conversions:
87+
88+
{% highlight scala %}
89+
jQuery.ajax(someURL, new JQueryAjaxSettings {
90+
override val crossDomain = true
91+
override val success = js.defined { (data, textStatus, xhr) =>
92+
println("Status: " + textStatus)
93+
}
94+
})
95+
{% endhighlight %}
96+
97+
## Export top-level functions
98+
99+
In Scala.js 0.6.13 and earlier, the only way to export something resembling a top-level function was to export the method and its enclosing object, as follows:
100+
101+
{% highlight scala %}
102+
@JSExport
103+
object Main {
104+
@JSExport
105+
def main(): Unit = { ... }
106+
}
107+
{% endhighlight %}
108+
109+
However, this requires to call it as `Main().main()` from JavaScript, which shows that it is not actually a top-level function.
110+
111+
In Scala.js 0.6.14, you can use the `@JSExportTopLevel` annotation instead:
112+
113+
{% highlight scala %}
114+
object Main {
115+
@JSExportTopLevel("main")
116+
def main(): Unit = { ... }
117+
}
118+
{% endhighlight %}
119+
120+
which allows to call `main()` from JavaScript.
121+
`@JSExportTopLevel` methods must be declared in top-level `object`s.
122+
123+
## Bug fixes
124+
125+
Among others, the following bugs have been fixed in 0.6.14:
126+
127+
* [#2587](https://github.com/scala-js/scala-js/issues/2587) Incorrect result for `BigDecimal` multiplication (corner case)
128+
* [#2639](https://github.com/scala-js/scala-js/issues/2639) The linker should refuse to build if `@JSImport` is used with `NoModule`
129+
* [#2640](https://github.com/scala-js/scala-js/issues/2640) `TimeoutException` when running PhantomJS with macOS Sierra
130+
* [#2643](https://github.com/scala-js/scala-js/issues/2643) `js.ThisFunction` passing Scala-`this` instead of JS-`this` when using Scala 2.12.0
131+
* [#2655](https://github.com/scala-js/scala-js/issues/2655) Inconsistent behavior in `NumericRange.min` method between JVM and JS
132+
* [#2689](https://github.com/scala-js/scala-js/issues/2689) The optimizer does something wrong with `return` inside `finally`
133+
134+
You can find the full list [on GitHub](https://github.com/scala-js/scala-js/issues?q=is%3Aissue+milestone%3Av0.6.14+is%3Aclosed).

assets/badges/scalajs-0.6.14.svg

Lines changed: 1 addition & 0 deletions
Loading

doc/all-api.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ title: All previous versions of the Scala.js API
55

66
## All previous versions of the API
77

8+
### Scala.js 0.6.14
9+
* [0.6.14 scalajs-library]({{ site.production_url }}/api/scalajs-library/0.6.14/#scala.scalajs.js.package)
10+
* [0.6.14 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/0.6.14/)
11+
* [0.6.14 scalajs-stubs]({{ site.production_url }}/api/scalajs-stubs/0.6.14/)
12+
* [0.6.14 scalajs-ir]({{ site.production_url }}/api/scalajs-ir/0.6.14/#org.scalajs.core.ir.package)
13+
* [0.6.14 scalajs-tools]({{ site.production_url }}/api/scalajs-tools/0.6.14/#org.scalajs.core.tools.package) ([Scala.js version]({{ site.production_url }}/api/scalajs-tools-js/0.6.14/#org.scalajs.core.tools.package))
14+
* [0.6.14 scalajs-js-envs]({{ site.production_url }}/api/scalajs-js-envs/0.6.14/#org.scalajs.jsenv.package)
15+
* [0.6.14 scalajs-js-envs-test-kit]({{ site.production_url }}/api/scalajs-js-envs-test-kit/0.6.14/#org.scalajs.jsenv.test.package)
16+
* [0.6.14 scalajs-test-adapter]({{ site.production_url }}/api/scalajs-sbt-test-adapter/0.6.14/#org.scalajs.testadapter.package)
17+
* [0.6.14 sbt-scalajs]({{ site.production_url }}/api/sbt-scalajs/0.6.14/#org.scalajs.sbtplugin.package)
18+
819
### Scala.js 0.6.13
920
* [0.6.13 scalajs-library]({{ site.production_url }}/api/scalajs-library/0.6.13/#scala.scalajs.js.package)
1021
* [0.6.13 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/0.6.13/)

doc/internals/downloads.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ We strongly recommend using the SBT plugin, as shown in the [bootstrapping skele
77

88
The CLI distribution requires `scala` and `scalac` (of the right major version) to be on the execution path. Unpack it wherever you like and add the `bin/` folder to your execution path.
99

10+
#### Scala.js 0.6.14
11+
* [0.6.14, Scala 2.11 (tgz, 26MB)]({{ site.production_url }}/files/scalajs_2.11-0.6.14.tgz)
12+
* [0.6.14, Scala 2.11 (zip, 26MB)]({{ site.production_url }}/files/scalajs_2.11-0.6.14.zip)
13+
* [0.6.14, Scala 2.10 (tgz, 22MB)]({{ site.production_url }}/files/scalajs_2.10-0.6.14.tgz)
14+
* [0.6.14, Scala 2.10 (zip, 22MB)]({{ site.production_url }}/files/scalajs_2.10-0.6.14.zip)
15+
1016
#### Scala.js 0.6.13
1117
* [0.6.13, Scala 2.11 (tgz, 26MB)]({{ site.production_url }}/files/scalajs_2.11-0.6.13.tgz)
1218
* [0.6.13, Scala 2.11 (zip, 26MB)]({{ site.production_url }}/files/scalajs_2.11-0.6.13.zip)

doc/internals/version-history.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ title: Version history
55

66
## Version history of Scala.js
77

8+
- [0.6.14](/news/2016/12/21/announcing-scalajs-0.6.14/)
89
- [0.6.13](/news/2016/10/17/announcing-scalajs-0.6.13/)
910
- [0.6.12](/news/2016/09/01/announcing-scalajs-0.6.12/)
1011
- [0.6.11](/news/2016/07/27/announcing-scalajs-0.6.11/)

doc/interoperability/export-to-javascript.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,27 @@ Not specifying `x` in this case will fail at runtime (since it does not have a d
269269

270270
Just like `@JSExport`, `@JSExportNamed` takes the name of the exported method as an optional argument.
271271

272+
## Exporting top-level methods
273+
274+
While an `@JSExport`ed method inside an `@JSExport`ed object allows JavaScript code to call a "static" method,
275+
it does not feel like a top-level function from JavaScript's point of view.
276+
`@JSExportTopLevel` allows to export a method of a top-level object as a truly top-level function:
277+
278+
{% highlight scala %}
279+
object A {
280+
@JSExportTopLevel("foo")
281+
def foo(x: Int): Int = x + 1
282+
}
283+
{% endhighlight %}
284+
285+
can be called from JavaScript as:
286+
287+
{% highlight javascript %}
288+
const y = foo(5);
289+
{% endhighlight %}
290+
291+
Note that `@JSExportTopLevel` requires an explicit name under which to export the function.
292+
272293
## Exporting properties
273294

274295
`val`s, `var`s and `def`s without parentheses, as well as `def`s whose name

doc/interoperability/sjs-defined-js-classes.md

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Scala.js-defined JS types have the following restrictions:
3434
* Private methods cannot be overloaded.
3535
* Qualified private members, i.e., `private[EnclosingScope]`, must be `final`.
3636
* Scala.js-defined JS classes, traits and objects cannot directly extend native JS traits (it is allowed to extend a native JS class).
37-
* Scala.js-defined JS traits cannot declare concrete term members, i.e., they must all be abstract.
37+
* Scala.js-defined JS traits cannot declare concrete term members (i.e., they must all be abstract) unless their right-hand-side is exactly `= js.undefined`.
3838
* Scala.js-defined JS classes and objects must extend a JS class, for example `js.Object` (they cannot directly extend `AnyRef with js.Any`).
3939
* Declaring a method named `apply` without `@JSName` is illegal.
4040
* Declaring a method with `@JSBracketSelect` or `@JSBracketCall` is illegal.
@@ -148,21 +148,61 @@ Native JS traits can only be extended by native JS classes, objects and traits.
148148
In other words, a Scala.js-defined JS class/trait/object cannot extend a native JS trait.
149149
They can only extend Scala.js-defined JS traits.
150150

151-
At the moment, Scala.js-defined JS traits cannot declare any concrete term members, i.e., all its `val`s, `var`s and `def`s must be abstract.
152-
So it is not possible to *mix in* traits into Scala.js-defined JS classes.
153-
You can only implement interfaces.
151+
Term members (`val`s, `var`s and `def`s) in Scala.js-defined JS traits must:
152+
153+
* either be abstract,
154+
* or have `= js.undefined` as right-hand-side (and not be a `def` with `()`).
154155

155156
{% highlight scala %}
156157
@ScalaJSDefined
157158
trait Bar extends js.Object {
158159
val x: Int
159160
val y: Int = 5 // illegal
161+
val z: js.UndefOr[Int] = js.undefined
160162

161163
def foo(x: Int): Int
162164
def bar(x: Int): Int = x + 1 // illegal
165+
def foobar(x: Int): js.UndefOr[Int] = js.undefined // illegal
166+
def babar: js.UndefOr[Int] = js.undefined
167+
}
168+
{% endhighlight %}
169+
170+
Unless overridden in a class or objects, concrete `val`s, `var`s and `def`s declared
171+
in a JavaScript trait (necessarily with `= js.undefined`) are *not* exposed to JavaScript at all.
172+
For example, implementing (the legal parts of) `Bar` in a subclass:
173+
174+
{% highlight scala %}
175+
@ScalaJSDefined
176+
class Babar extends Bar {
177+
val x: Int = 42
178+
179+
def foo(x: Int): Int = x + 1
180+
181+
override def babar: js.UndefOr[Int] = 3
182+
}
183+
{% endhighlight %}
184+
185+
has the same semantics as the following ECMAScript 2015 class:
186+
187+
{% highlight javascript %}
188+
class Babar extends global.Object { // `extends Bar` disappears
189+
constructor() {
190+
super();
191+
this.x = 42;
192+
}
193+
foo(x) {
194+
return x + 1;
195+
}
196+
get babar() {
197+
return 3;
198+
}
163199
}
164200
{% endhighlight %}
165201

202+
Note that `z` is not defined at all, not even as `this.z = undefined`.
203+
The distinction is rarely relevant, because `babar.z` will return `undefined` in JavaScript
204+
and in Scala.js if `babar` does not have a field `z`.
205+
166206

167207
### Anonymous classes
168208

@@ -183,6 +223,50 @@ val pos = new Position {
183223
}
184224
{% endhighlight %}
185225

226+
#### Use case: configuration objects
227+
228+
For configuration objects that have fields with default values, concrete members with `= js.undefined` can be used in the trait.
229+
For example:
230+
231+
{% highlight scala %}
232+
@ScalaJSDefined
233+
trait JQueryAjaxSettings extends js.Object {
234+
val data: js.UndefOr[js.Object | String | js.Array[Any]] = js.undefined
235+
val contentType: js.UndefOr[Boolean | String] = js.undefined
236+
val crossDomain: js.UndefOr[Boolean] = js.undefined
237+
val success: js.UndefOr[js.Function3[Any, String, JQueryXHR, _]] = js.undefined
238+
...
239+
}
240+
{% endhighlight %}
241+
242+
When calling `ajax()`, we can now give an anonymous object that overrides only the `val`s we care about:
243+
244+
{% highlight scala %}
245+
jQuery.ajax(someURL, new JQueryAjaxSettings {
246+
override val crossDomain: js.UndefOr[Boolean] = true
247+
override val success: js.UndefOr[js.Function3[Any, String, JQueryXHR, _]] = {
248+
js.defined { (data: Any, textStatus: String, xhr: JQueryXHR) =>
249+
println("Status: " + textStatus)
250+
}
251+
}
252+
})
253+
{% endhighlight %}
254+
255+
Note that for functions, we use `js.defined { ... }` to drive Scala's type inference.
256+
Otherwise, it needs to apply two implicit conversions, which is not allowed.
257+
258+
The explicit types are quite annoying, but they are only necessary in Scala 2.10 and 2.11.
259+
If you use Scala 2.12, you can omit all the type annotations (but keep `js.defined`), thanks to improved type inference for `val`s and SAM conversions:
260+
261+
{% highlight scala %}
262+
jQuery.ajax(someURL, new JQueryAjaxSettings {
263+
override val crossDomain = true
264+
override val success = js.defined { (data, textStatus, xhr) =>
265+
println("Status: " + textStatus)
266+
}
267+
})
268+
{% endhighlight %}
269+
186270
#### Caveat with reflective calls
187271

188272
It is possible to *define* an object literal with the anonymous class syntax without the support of a super class or trait defining the API, like this:

0 commit comments

Comments
 (0)