From 2c98590065e86dff64aaeb6ea524065c495dcc8b Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Sat, 25 Apr 2015 07:56:25 -0400 Subject: [PATCH] [[FEAT]] support destructuring in ForIn/Of loops, lint bad ForIn/Of LHS --- src/jshint.js | 104 ++++--- src/messages.js | 3 +- tests/unit/core.js | 34 ++- tests/unit/parser.js | 714 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 808 insertions(+), 47 deletions(-) diff --git a/src/jshint.js b/src/jshint.js index 96666792f6..c743194ee3 100644 --- a/src/jshint.js +++ b/src/jshint.js @@ -3452,25 +3452,23 @@ var JSHINT = (function() { } } } - if (prefix) { - break; - } this.first = this.first.concat(names); - if (state.tokens.next.id !== "=") { + if (!prefix && state.tokens.next.id !== "=") { warning("E012", state.tokens.curr, state.tokens.curr.value); } if (state.tokens.next.id === "=") { advance("="); - if (state.tokens.next.id === "undefined") { + if (!prefix && state.tokens.next.id === "undefined") { warning("W080", state.tokens.prev, state.tokens.prev.value); } - if (peek(0).id === "=" && state.tokens.next.identifier) { + if (!prefix && peek(0).id === "=" && state.tokens.next.identifier) { warning("W120", state.tokens.next, state.tokens.next.value); } - value = expression(10); + // don't accept `in` in expression if prefix is used for ForIn/Of loop. + value = expression(prefix ? 120 : 10); if (lone) { tokens[0].first = value; } else { @@ -3494,6 +3492,10 @@ var JSHINT = (function() { var inexport = context && context.inexport; var tokens, lone, value; + // If the `implied` option is set, bindings are set differently. + var implied = context && context.implied; + var report = implied !== "ignore"; + this.first = []; for (;;) { var names = []; @@ -3514,7 +3516,7 @@ var JSHINT = (function() { if (state.option.inESNext() && funct[t.id] === "const") { warning("E011", null, t.id); } - if (funct["(global)"]) { + if (!implied && funct["(global)"]) { if (predefined[t.id] === false) { warning("W079", t.token, t.id); } else if (state.option.futurehostile === false) { @@ -3525,16 +3527,29 @@ var JSHINT = (function() { } } if (t.id) { - addlabel(t.id, { type: "unused", token: t.token }); + if (implied === "for") { + var ident = t.token.value; + switch (funct[ident]) { + case "unused": + funct[ident] = "var"; + break; + case "var": + break; + default: + if (!funct["(blockscope)"].getlabel(ident) && + !(scope[ident] || {})[ident]) { + if (report) warning("W088", t.token, ident); + } + } + } else { + addlabel(t.id, { type: "unused", token: t.token }); + } names.push(t.token); } } } - if (prefix) { - break; - } - if (state.option.varstmt) { + if (!prefix && report && state.option.varstmt) { warning("W132", this); } @@ -3543,15 +3558,17 @@ var JSHINT = (function() { if (state.tokens.next.id === "=") { state.nameStack.set(state.tokens.curr); advance("="); - if (state.tokens.next.id === "undefined") { + if (!prefix && report && state.tokens.next.id === "undefined") { warning("W080", state.tokens.prev, state.tokens.prev.value); } if (peek(0).id === "=" && state.tokens.next.identifier) { - if (!funct["(params)"] || funct["(params)"].indexOf(state.tokens.next.value) === -1) { + if (!prefix && report && + !funct["(params)"] || funct["(params)"].indexOf(state.tokens.next.value) === -1) { warning("W120", state.tokens.next, state.tokens.next.value); } } - value = expression(10); + // don't accept `in` in expression if prefix is used for ForIn/Of loop. + value = expression(prefix ? 120 : 10); if (lone) { tokens[0].first = value; } else { @@ -3617,21 +3634,19 @@ var JSHINT = (function() { } } } - if (prefix) { - break; - } this.first = this.first.concat(names); if (state.tokens.next.id === "=") { advance("="); - if (state.tokens.next.id === "undefined") { + if (!prefix && state.tokens.next.id === "undefined") { warning("W080", state.tokens.prev, state.tokens.prev.value); } - if (peek(0).id === "=" && state.tokens.next.identifier) { + if (!prefix && peek(0).id === "=" && state.tokens.next.identifier) { warning("W120", state.tokens.next, state.tokens.next.value); } - value = expression(10); + // don't accept `in` in expression if prefix is used for ForIn/Of loop. + value = expression(prefix ? 120 : 10); if (lone) { tokens[0].first = value; } else { @@ -4175,10 +4190,24 @@ var JSHINT = (function() { var nextop; // contains the token of the "in" or "of" operator var i = 0; var inof = ["in", "of"]; + var level = 0; // BindingPattern "level" --- level 0 === no BindingPattern + var comma; // First comma punctuator at level 0 + var initializer; // First initializer at level 0 + + // If initial token is a BindingPattern, count it as such. + if (checkPunctuators(state.tokens.next, ["{", "["])) ++level; do { nextop = peek(i); ++i; - } while (!_.contains(inof, nextop.value) && nextop.value !== ";" && nextop.type !== "(end)"); + if (checkPunctuators(nextop, ["{", "["])) ++level; + else if (checkPunctuators(nextop, ["}", "]"])) --level; + if (level < 0) break; + if (level === 0) { + if (!comma && checkPunctuators(nextop, [","])) comma = nextop; + else if (!initializer && checkPunctuators(nextop, ["="])) initializer = nextop; + } + } while (level > 0 || !_.contains(inof, nextop.value) && nextop.value !== ";" && + nextop.type !== "(end)"); // Is this a JSCS bug? This looks really weird. // if we're in a for (… in|of …) statement if (_.contains(inof, nextop.value)) { @@ -4186,6 +4215,15 @@ var JSHINT = (function() { error("W104", nextop, "for of"); } + var ok = !(initializer || comma); + if (initializer) { + error("W133", comma, nextop.value, "initializer is forbidden"); + } + + if (comma) { + error("W133", comma, nextop.value, "more than one ForBinding"); + } + if (state.tokens.next.id === "var") { advance("var"); state.tokens.curr.fud({ prefix: true }); @@ -4195,24 +4233,10 @@ var JSHINT = (function() { letscope = true; funct["(blockscope)"].stack(); state.tokens.curr.fud({ prefix: true }); - } else if (!state.tokens.next.identifier) { - error("E030", state.tokens.next, state.tokens.next.type); - advance(); } else { - switch (funct[state.tokens.next.value]) { - case "unused": - funct[state.tokens.next.value] = "var"; - break; - case "var": - break; - default: - var ident = state.tokens.next.value; - if (!funct["(blockscope)"].getlabel(ident) && - !(scope[ident] || {})[ident]) { - warning("W088", state.tokens.next, state.tokens.next.value); - } - } - advance(); + // Parse as a var statement, with implied bindings. Ignore errors if an error + // was already reported + Object.create(varstatement).fud({ prefix: true, implied: ok ? "for" : "ignore" }); } advance(nextop.value); expression(20); diff --git a/src/messages.js b/src/messages.js index f2c5e1cc66..35d7a16efd 100644 --- a/src/messages.js +++ b/src/messages.js @@ -207,7 +207,8 @@ var warnings = { "different variable name to avoid migration issues.", W130: "Invalid element after rest element.", W131: "Invalid parameter after rest parameter.", - W132: "`var` declarations are forbidden. Use `let` or `const` instead." + W132: "`var` declarations are forbidden. Use `let` or `const` instead.", + W133: "Invalid for-{a} loop left-hand-side: {b}." }; var info = { diff --git a/tests/unit/core.js b/tests/unit/core.js index 8ffb111b8e..156dcb2c7e 100644 --- a/tests/unit/core.js +++ b/tests/unit/core.js @@ -633,9 +633,41 @@ exports.testForIn = function (test) { ]; TestRun(test) - .addError(2, "Expected an identifier and instead saw '(string)'.") + .addError(2, "Expected an identifier and instead saw 'i'.") .test(src); + src = [ + "(function (o) {", + "for (i, j in o) { i(); }", + "for (var x, u in o) { x(); }", + "for (z = 0 in o) { z(); }", + "for (var q = 0 in o) { q(); }", + "})();" + ]; + + TestRun(test, "bad lhs errors") + .addError(2, "Invalid for-in loop left-hand-side: more than one ForBinding.") + .addError(3, "Invalid for-in loop left-hand-side: more than one ForBinding.") + .addError(4, "Invalid for-in loop left-hand-side: initializer is forbidden.") + .addError(5, "Invalid for-in loop left-hand-side: initializer is forbidden.") + .test(src); + + src = [ + "(function (o) {", + "for (let i, j in o) { i(); }", + "for (const x, u in o) { x(); }", + "for (let z = 0 in o) { z(); }", + "for (const q = 0 in o) { q(); }", + "})();" + ]; + + TestRun(test, "bad lhs errors (lexical)") + .addError(2, "Invalid for-in loop left-hand-side: more than one ForBinding.") + .addError(3, "Invalid for-in loop left-hand-side: more than one ForBinding.") + .addError(4, "Invalid for-in loop left-hand-side: initializer is forbidden.") + .addError(5, "Invalid for-in loop left-hand-side: initializer is forbidden.") + .test(src, { esnext: true }); + test.done(); }; diff --git a/tests/unit/parser.js b/tests/unit/parser.js index 180ba767ef..7b15f723cd 100644 --- a/tests/unit/parser.js +++ b/tests/unit/parser.js @@ -3659,9 +3659,37 @@ exports["for of as esnext"] = function (test) { " print(x);", "}", "for (let x of [1,2,3,4]) print(x);", - "for (const x of [1,2,3,4]) print(x);" - ]; - TestRun(test) + "for (const x of [1,2,3,4]) print(x);", + "for (x = 1 of [1,2,3,4]) print(x);", + "for (x, y of [1,2,3,4]) print(x + y);", + "for (x = 1, y = 2 of [1,2,3,4]) print(x + y);", + "for (var x = 1 of [1,2,3,4]) print(x);", + "for (var x, y of [1,2,3,4]) print(x + y);", + "for (var x = 1, y = 2 of [1,2,3,4]) print(x + y);", + "for (let x = 1 of [1,2,3,4]) print(x);", + "for (let x, y of [1,2,3,4]) print(x + y);", + "for (let x = 1, y = 2 of [1,2,3,4]) print(x + y);", + "for (const x = 1 of [1,2,3,4]) print(x);", + "for (const x, y of [1,2,3,4]) print(x + y);", + "for (const x = 1, y = 2 of [1,2,3,4]) print(x + y);" + ]; + TestRun(test) + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(7, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(8, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(8, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(9, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(10, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(11, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(11, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(12, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(13, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(14, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(14, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(15, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(16, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(17, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(17, "Invalid for-of loop left-hand-side: more than one ForBinding.") .test(code, {esnext: true, undef: true, predef: ["print"]}); test.done(); @@ -3673,7 +3701,19 @@ exports["for of as es5"] = function (test) { " print(x);", "}", "for (let x of [1,2,3,4]) print(x);", - "for (const x of [1,2,3,4]) print(x);" + "for (const x of [1,2,3,4]) print(x);", + "for (x = 1 of [1,2,3,4]) print(x);", + "for (x, y of [1,2,3,4]) print(x + y);", + "for (x = 1, y = 2 of [1,2,3,4]) print(x + y);", + "for (var x = 1 of [1,2,3,4]) print(x);", + "for (var x, y of [1,2,3,4]) print(x + y);", + "for (var x = 1, y = 2 of [1,2,3,4]) print(x + y);", + "for (let x = 1 of [1,2,3,4]) print(x);", + "for (let x, y of [1,2,3,4]) print(x + y);", + "for (let x = 1, y = 2 of [1,2,3,4]) print(x + y);", + "for (const x = 1 of [1,2,3,4]) print(x);", + "for (const x, y of [1,2,3,4]) print(x + y);", + "for (const x = 1, y = 2 of [1,2,3,4]) print(x + y);" ]; TestRun(test) .addError(1, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") @@ -3682,6 +3722,40 @@ exports["for of as es5"] = function (test) { .addError(4, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") .addError(5, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(7, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(8, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(8, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(9, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(10, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(10, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(11, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(11, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(11, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(12, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(12, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(12, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(13, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(13, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(13, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(14, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(14, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(14, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(14, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(15, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(15, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(15, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(16, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(16, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(16, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(17, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(17, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(17, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(17, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") .test(code, {undef: true, predef: ["print"]}); // es5 test.done(); @@ -3693,7 +3767,19 @@ exports["for of as legacy JS"] = function (test) { " print(x);", "}", "for (let x of [1,2,3,4]) print(x);", - "for (const x of [1,2,3,4]) print(x);" + "for (const x of [1,2,3,4]) print(x);", + "for (x = 1 of [1,2,3,4]) print(x);", + "for (x, y of [1,2,3,4]) print(x + y);", + "for (x = 1, y = 2 of [1,2,3,4]) print(x + y);", + "for (var x = 1 of [1,2,3,4]) print(x);", + "for (var x, y of [1,2,3,4]) print(x + y);", + "for (var x = 1, y = 2 of [1,2,3,4]) print(x + y);", + "for (let x = 1 of [1,2,3,4]) print(x);", + "for (let x, y of [1,2,3,4]) print(x + y);", + "for (let x = 1, y = 2 of [1,2,3,4]) print(x + y);", + "for (const x = 1 of [1,2,3,4]) print(x);", + "for (const x, y of [1,2,3,4]) print(x + y);", + "for (const x = 1, y = 2 of [1,2,3,4]) print(x + y);" ]; TestRun(test) .addError(1, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") @@ -3702,11 +3788,629 @@ exports["for of as legacy JS"] = function (test) { .addError(4, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") .addError(5, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(7, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(8, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(8, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(9, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(10, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(10, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(11, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(11, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(11, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(12, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(12, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(12, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(13, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(13, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(13, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(14, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(14, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(14, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(14, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(15, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(15, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(15, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(16, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(16, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(16, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(17, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(17, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(17, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(17, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") .test(code, {undef: true, predef: ["print"]}); // es5 test.done(); }; +exports["array destructuring for of as esnext"] = function (test) { + var basic = [ + "for ([i, v] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (var [i, v] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (let [i, v] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (const [i, v] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);" + ]; + + TestRun(test, "basic") + .addError(1, "Creating global 'for' variable. Should be 'for (var i ...'.") + .addError(1, "Creating global 'for' variable. Should be 'for (var v ...'.") + .test(basic, {esnext: true, undef: true, predef: ["print"]}); + + var bad = [ + "for ([i, v] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for ([i, v], [a, b] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for ([i, v], [a, b] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (var [i, v] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (var [i, v], [a, b] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (var [i, v], [a, b] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + ]; + + TestRun(test, "errors #1") + .addError(1, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(2, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(3, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(3, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .test(bad, {esnext: true, undef: true, predef: ["print"]}); + + var bad2 = [ + "for (let [i, v] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (let [i, v], [a, b] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (let [i, v], [a, b] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (const [i, v] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (const [i, v], [a, b] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (const [i, v], [a, b] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + ]; + TestRun(test, "errors #2") + .addError(1, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(2, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(3, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(3, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .test(bad2, {esnext: true, undef: true, predef: ["print"]}); + + test.done(); +}; + +exports["array destructuring for of as es5"] = function (test) { + var basic = [ + "for ([i, v] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (var [i, v] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (let [i, v] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (const [i, v] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);" + ]; + + TestRun(test, "basic") + .addError(1, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(1, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(1, "Creating global 'for' variable. Should be 'for (var i ...'.") + .addError(1, "Creating global 'for' variable. Should be 'for (var v ...'.") + .addError(2, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .test(basic, {undef: true, predef: ["print"]}); // es5 + + var bad = [ + "for ([i, v] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for ([i, v], [a, b] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for ([i, v], [a, b] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (var [i, v] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (var [i, v], [a, b] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (var [i, v], [a, b] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + ]; + + TestRun(test, "errors #1") + .addError(1, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(1, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(1, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(2, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(3, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(3, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .test(bad, {undef: true, predef: ["print"]}); // es5 + + var bad2 = [ + "for (let [i, v] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (let [i, v], [a, b] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (let [i, v], [a, b] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (const [i, v] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (const [i, v], [a, b] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (const [i, v], [a, b] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + ]; + TestRun(test, "errors #2") + .addError(1, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(1, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(1, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(1, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(2, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(3, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(3, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(4, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(5, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(6, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .test(bad2, {undef: true, predef: ["print"]}); // es5 + + test.done(); +}; + +exports["array destructuring for of as legacy JS"] = function (test) { + var basic = [ + "for ([i, v] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (var [i, v] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (let [i, v] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (const [i, v] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);" + ]; + + TestRun(test, "basic") + .addError(1, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(1, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(1, "Creating global 'for' variable. Should be 'for (var i ...'.") + .addError(1, "Creating global 'for' variable. Should be 'for (var v ...'.") + .addError(2, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .test(basic, {es3: true, undef: true, predef: ["print"]}); // es3 + + var bad = [ + "for ([i, v] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for ([i, v], [a, b] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for ([i, v], [a, b] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (var [i, v] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (var [i, v], [a, b] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (var [i, v], [a, b] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + ]; + + TestRun(test, "errors #1") + .addError(1, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(1, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(1, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(2, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(3, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(3, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .test(bad, {es3: true, undef: true, predef: ["print"]}); // es3 + + var bad2 = [ + "for (let [i, v] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (let [i, v], [a, b] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (let [i, v], [a, b] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (const [i, v] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (const [i, v], [a, b] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + "for (const [i, v], [a, b] = [1, 2] of [[0, 1],[1, 2],[2, 3],[3, 4]]) print(i + '=' + v);", + ]; + TestRun(test, "errors #2") + .addError(1, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(1, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(1, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(1, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(2, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(2, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(3, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(3, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(3, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(4, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(5, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(6, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .test(bad2, {es3: true, undef: true, predef: ["print"]}); // es3 + + test.done(); +}; + +exports["object destructuring for of as esnext"] = function (test) { + var basic = [ + "var obj1 = { key: 'a', data: { value: 1 } };", + "var obj2 = { key: 'b', data: { value: 2 } };", + "var arr = [obj1, obj2];", + "for ({key, data: { value } } of arr) print(key + '=' + value);", + "for (var {key, data: { value } } of arr) print(key + '=' + value);", + "for (let {key, data: { value } } of arr) print(key + '=' + value);", + "for (const {key, data: { value } } of arr) print(key + '=' + value);" + ]; + + TestRun(test, "basic") + .addError(4, "Creating global 'for' variable. Should be 'for (var key ...'.") + .addError(4, "Creating global 'for' variable. Should be 'for (var value ...'.") + .test(basic, {esnext: true, undef: true, predef: ["print"]}); + + var bad = [ + "var obj1 = { key: 'a', data: { val: 1 } };", + "var obj2 = { key: 'b', data: { val: 2 } };", + "var arr = [obj1, obj2];", + "for ({key, data: {val}} = obj1 of arr) print(key + '=' + val);", + "for ({key, data: {val}}, {a, b} of arr) print(key + '=' + val);", + "for ({key, data: {val}}, {a, b} = obj1 of arr) print(key + '=' + val);", + "for (var {key, data: {val}} = obj1 of arr) print(key + '=' + val);", + "for (var {key, data: {val}}, {a, b} of arr) print(key + '=' + val);", + "for (var {key, data: {val}}, {a, b} = obj1 of arr) print(key + '=' + val);" + ]; + + TestRun(test, "errors #1") + .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(7, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(8, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(9, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(9, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .test(bad, {esnext: true, undef: true, predef: ["print"]}); + + var bad2 = [ + "var obj1 = { key: 'a', data: { val: 1 } };", + "var obj2 = { key: 'b', data: { val: 2 } };", + "var arr = [obj1, obj2];", + "for (let {key, data: {val}} = obj1 of arr) print(key + '=' + val);", + "for (let {key, data: {val}}, {a, b} of arr) print(key + '=' + val);", + "for (let {key, data: {val}}, {a, b} = obj1 of arr) print(key + '=' + val);", + "for (const {key, data: {val}} = obj1 of arr) print(key + '=' + val);", + "for (const {key, data: {val}}, {a, b} of arr) print(key + '=' + val);", + "for (const {key, data: {val}}, {a, b} = obj1 of arr) print(key + '=' + val);" + ]; + + TestRun(test, "errors #2") + .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(7, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(8, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(9, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(9, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .test(bad2, {esnext: true, undef: true, predef: ["print"]}); + + test.done(); +}; + +exports["object destructuring for of as es5"] = function (test) { + var basic = [ + "var obj1 = { key: 'a', data: { value: 1 } };", + "var obj2 = { key: 'b', data: { value: 2 } };", + "var arr = [obj1, obj2];", + "for ({key, data: { value } } of arr) print(key + '=' + value);", + "for (var {key, data: { value } } of arr) print(key + '=' + value);", + "for (let {key, data: { value } } of arr) print(key + '=' + value);", + "for (const {key, data: { value } } of arr) print(key + '=' + value);" + ]; + + TestRun(test, "basic") + .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "Creating global 'for' variable. Should be 'for (var key ...'.") + .addError(4, "Creating global 'for' variable. Should be 'for (var value ...'.") + .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .test(basic, {undef: true, predef: ["print"]}); // es5 + + var bad = [ + "var obj1 = { key: 'a', data: { val: 1 } };", + "var obj2 = { key: 'b', data: { val: 2 } };", + "var arr = [obj1, obj2];", + "for ({key, data: {val}} = obj1 of arr) print(key + '=' + val);", + "for ({key, data: {val}}, {a, b} of arr) print(key + '=' + val);", + "for ({key, data: {val}}, {a, b} = obj1 of arr) print(key + '=' + val);", + "for (var {key, data: {val}} = obj1 of arr) print(key + '=' + val);", + "for (var {key, data: {val}}, {a, b} of arr) print(key + '=' + val);", + "for (var {key, data: {val}}, {a, b} = obj1 of arr) print(key + '=' + val);" + ]; + + TestRun(test, "errors #1") + .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(7, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(8, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(9, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(9, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .test(bad, {undef: true, predef: ["print"]}); // es5 + + var bad2 = [ + "var obj1 = { key: 'a', data: { val: 1 } };", + "var obj2 = { key: 'b', data: { val: 2 } };", + "var arr = [obj1, obj2];", + "for (let {key, data: {val}} = obj1 of arr) print(key + '=' + val);", + "for (let {key, data: {val}}, {a, b} of arr) print(key + '=' + val);", + "for (let {key, data: {val}}, {a, b} = obj1 of arr) print(key + '=' + val);", + "for (const {key, data: {val}} = obj1 of arr) print(key + '=' + val);", + "for (const {key, data: {val}}, {a, b} of arr) print(key + '=' + val);", + "for (const {key, data: {val}}, {a, b} = obj1 of arr) print(key + '=' + val);" + ]; + + TestRun(test, "errors #2") + .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(4, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(5, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(6, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(7, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(8, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(9, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(9, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .test(bad2, {undef: true, predef: ["print"]}); // es5 + + test.done(); +}; + +exports["object destructuring for of as legacy JS"] = function (test) { + var basic = [ + "var obj1 = { key: 'a', data: { value: 1 } };", + "var obj2 = { key: 'b', data: { value: 2 } };", + "var arr = [obj1, obj2];", + "for ({key, data: { value } } of arr) print(key + '=' + value);", + "for (var {key, data: { value } } of arr) print(key + '=' + value);", + "for (let {key, data: { value } } of arr) print(key + '=' + value);", + "for (const {key, data: { value } } of arr) print(key + '=' + value);" + ]; + + TestRun(test, "basic") + .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "Creating global 'for' variable. Should be 'for (var key ...'.") + .addError(4, "Creating global 'for' variable. Should be 'for (var value ...'.") + .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .test(basic, {es3: true, undef: true, predef: ["print"]}); // es3 + + var bad = [ + "var obj1 = { key: 'a', data: { val: 1 } };", + "var obj2 = { key: 'b', data: { val: 2 } };", + "var arr = [obj1, obj2];", + "for ({key, data: {val}} = obj1 of arr) print(key + '=' + val);", + "for ({key, data: {val}}, {a, b} of arr) print(key + '=' + val);", + "for ({key, data: {val}}, {a, b} = obj1 of arr) print(key + '=' + val);", + "for (var {key, data: {val}} = obj1 of arr) print(key + '=' + val);", + "for (var {key, data: {val}}, {a, b} of arr) print(key + '=' + val);", + "for (var {key, data: {val}}, {a, b} = obj1 of arr) print(key + '=' + val);" + ]; + + TestRun(test, "errors #1") + .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(7, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(8, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(9, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(9, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .test(bad, {es3: true, undef: true, predef: ["print"]}); // es3 + + var bad2 = [ + "var obj1 = { key: 'a', data: { val: 1 } };", + "var obj2 = { key: 'b', data: { val: 2 } };", + "var arr = [obj1, obj2];", + "for (let {key, data: {val}} = obj1 of arr) print(key + '=' + val);", + "for (let {key, data: {val}}, {a, b} of arr) print(key + '=' + val);", + "for (let {key, data: {val}}, {a, b} = obj1 of arr) print(key + '=' + val);", + "for (const {key, data: {val}} = obj1 of arr) print(key + '=' + val);", + "for (const {key, data: {val}}, {a, b} of arr) print(key + '=' + val);", + "for (const {key, data: {val}}, {a, b} = obj1 of arr) print(key + '=' + val);" + ]; + + TestRun(test, "errors #2") + .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(4, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(4, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(5, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(5, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(6, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(6, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(6, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(7, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(7, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(8, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(8, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "Invalid for-of loop left-hand-side: initializer is forbidden.") + .addError(9, "Invalid for-of loop left-hand-side: more than one ForBinding.") + .addError(9, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .addError(9, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).") + .test(bad2, {es3: true, undef: true, predef: ["print"]}); // es3 + + test.done(); +}; + exports["try multi-catch for moz extensions"] = function (test) { var code = [ "try {",