/*
* Copyright 2015 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.jscomp.CompilerOptions.LanguageMode;
public class Es6RewriteArrowFunctionTest extends CompilerTestCase {
private LanguageMode languageOut;
@Override
public void setUp() {
setAcceptedLanguage(LanguageMode.ECMASCRIPT_2015);
languageOut = LanguageMode.ECMASCRIPT3;
disableTypeCheck();
runTypeCheckAfterProcessing = true;
}
@Override
protected CompilerOptions getOptions() {
CompilerOptions options = super.getOptions();
options.setLanguageOut(languageOut);
return options;
}
@Override
protected Es6RewriteArrowFunction getProcessor(Compiler compiler) {
return new Es6RewriteArrowFunction(compiler);
}
public void testArrowFunction() {
test("var f = x => { return x+1; };", "var f = function(x) { return x+1; };");
test("var odds = [1,2,3,4].filter((n) => n%2 == 1);",
"var odds = [1,2,3,4].filter(function(n) { return n%2 == 1; });");
test("var f = x => x+1;", "var f = function(x) { return x+1; };");
test("var f = () => this;",
"const $jscomp$this = this; var f = function() { return $jscomp$this; };");
test(
"var f = x => { this.needsBinding(); return 0; };",
LINE_JOINER.join(
"const $jscomp$this = this;",
"var f = function(x) {",
" $jscomp$this.needsBinding();",
" return 0;",
"};"));
test(
LINE_JOINER.join(
"var f = x => {", " this.init();", " this.doThings();", " this.done();", "};"),
LINE_JOINER.join(
"const $jscomp$this = this;",
"var f = function(x) {",
" $jscomp$this.init();",
" $jscomp$this.doThings();",
" $jscomp$this.done();",
"};"));
test(
"switch(a) { case b: (() => { this; })(); }",
LINE_JOINER.join(
"const $jscomp$this = this;",
"switch(a) {",
" case b:",
" (function() { $jscomp$this; })();",
"}"));
test(
LINE_JOINER.join(
"switch(a) {",
" case b:",
" (() => { this; })();",
" case c:",
" (() => { this; })();",
"}"),
LINE_JOINER.join(
"const $jscomp$this = this;",
"switch(a) {",
" case b:",
" (function() { $jscomp$this; })();",
" case c:",
" (function() { $jscomp$this; })();",
"}"));
test(
LINE_JOINER.join(
"switch(a) {",
" case b:",
" (() => { this; })();",
"}",
"switch (c) {",
" case d:",
" (() => { this; })();",
"}"),
LINE_JOINER.join(
"const $jscomp$this = this;",
"switch(a) {",
" case b:",
" (function() { $jscomp$this; })();",
"}",
"switch (c) {",
" case d:",
" (function() { $jscomp$this; })();",
"}"));
}
public void testArguments() {
test(
LINE_JOINER.join(
"function f() {",
" var x = () => arguments;",
"}"),
LINE_JOINER.join(
"function f() {",
" /** @type {!Arguments} */",
" const $jscomp$arguments = arguments;",
" var x = function() { return $jscomp$arguments; };",
"}"));
}
public void testArrowFunctionInObject() {
test("var obj = { f: () => 'bar' };",
"var obj = { f: function() { return 'bar'; } };");
}
public void testArrowInClass() {
test(
LINE_JOINER.join(
"class C {",
" constructor() {",
" this.counter = 0;",
" }",
"",
" init() {",
" document.onclick = () => this.logClick();",
" }",
"",
" logClick() {",
" this.counter++;",
" }",
"}"),
LINE_JOINER.join(
"class C {",
" constructor() {",
" this.counter = 0;",
" }",
"",
" init() {",
" const $jscomp$this = this;",
" document.onclick = function() {return $jscomp$this.logClick()}",
" }",
"",
" logClick() {",
" this.counter++;",
" }",
"}"));
}
public void testArrowInConstructorWithSuperCall() {
test(
LINE_JOINER.join(
"class B {",
" constructor(x) {",
" this.x = x;",
" }",
"}",
"class C extends B {",
" constructor(x, y) {",
" console.log('statement before super');",
" super(x);",
" this.wrappedXGetter = () => this.x;",
" this.y = y;",
" this.wrappedYGetter = () => this.y;",
" }",
"}"),
LINE_JOINER.join(
"class B {",
" constructor(x) {",
" this.x = x;",
" }",
"}",
"class C extends B {",
" constructor(x, y) {",
" console.log('statement before super');",
" super(x);",
" const $jscomp$this = this;", // Must not use `this` before super() call.
" this.wrappedXGetter = function() { return $jscomp$this.x; };",
" this.y = y;",
" this.wrappedYGetter = function() { return $jscomp$this.y; };",
" }",
"}"));
test(
LINE_JOINER.join(
"class B {",
" constructor(x) {",
" this.x = x;",
" }",
"}",
"class C extends B {",
" constructor(x, y) {",
" if (x < 1) {",
" super(x);",
" } else {",
" super(-x);",
" }",
" this.wrappedXGetter = () => this.x;",
" this.y = y;",
" this.wrappedYGetter = () => this.y;",
" }",
"}"),
LINE_JOINER.join(
"class B {",
" constructor(x) {",
" this.x = x;",
" }",
"}",
"class C extends B {",
" constructor(x, y) {",
" if (x < 1) {",
" super(x);",
" } else {",
" super(-x);",
" }",
" const $jscomp$this = this;", // Must not use `this` before super() call.
" this.wrappedXGetter = function() { return $jscomp$this.x; };",
" this.y = y;",
" this.wrappedYGetter = function() { return $jscomp$this.y; };",
" }",
"}"));
}
public void testMultipleArrowsInSameScope() {
test(
"var a1 = x => x+1; var a2 = x => x-1;",
"var a1 = function(x) { return x+1; }; var a2 = function(x) { return x-1; };");
test(
"function f() { var a1 = x => x+1; var a2 = x => x-1; }",
LINE_JOINER.join(
"function f() {",
" var a1 = function(x) { return x+1; };",
" var a2 = function(x) { return x-1; };",
"}"));
test(
"function f() { var a1 = () => this.x; var a2 = () => this.y; }",
LINE_JOINER.join(
"function f() {",
" const $jscomp$this = this;",
" var a1 = function() { return $jscomp$this.x; };",
" var a2 = function() { return $jscomp$this.y; };",
"}"));
test(
"var a = [1,2,3,4]; var b = a.map(x => x+1).map(x => x*x);",
LINE_JOINER.join(
"var a = [1,2,3,4];",
"var b = a.map(function(x) { return x+1; }).map(function(x) { return x*x; });"));
test(
LINE_JOINER.join(
"function f() {",
" var a = [1,2,3,4];",
" var b = a.map(x => x+1).map(x => x*x);",
"}"),
LINE_JOINER.join(
"function f() {",
" var a = [1,2,3,4];",
" var b = a.map(function(x) { return x+1; }).map(function(x) { return x*x; });",
"}"));
}
public void testArrowNestedScope() {
test(
LINE_JOINER.join(
"var outer = {",
" f: function() {",
" var a1 = () => this.x;",
" var inner = {",
" f: function() {",
" var a2 = () => this.y;",
" }",
" };",
" }",
"}"),
LINE_JOINER.join(
"var outer = {",
" f: function() {",
" const $jscomp$this = this;",
" var a1 = function() { return $jscomp$this.x; }",
" var inner = {",
" f: function() {",
" const $jscomp$this = this;",
" var a2 = function() { return $jscomp$this.y; }",
" }",
" };",
" }",
"}"));
test(
LINE_JOINER.join(
"function f() {",
" var setup = () => {",
" function Foo() { this.x = 5; }",
" this.f = new Foo;",
" }",
"}"),
LINE_JOINER.join(
"function f() {",
" const $jscomp$this = this;",
" var setup = function() {",
" function Foo() { this.x = 5; }",
" $jscomp$this.f = new Foo;",
" }",
"}"));
}
public void testArrowception() {
test("var f = x => y => x+y;",
"var f = function(x) {return function(y) { return x+y; }; };");
}
public void testArrowceptionWithThis() {
test(
"var f = (x => { var g = (y => { this.foo(); }) });",
LINE_JOINER.join(
"const $jscomp$this = this;",
"var f = function(x) {",
" var g = function(y) {",
" $jscomp$this.foo();",
" }",
"}"));
}
}