Skip to content

Commit

Permalink
[[FIX]] Allow object destructuring assignment
Browse files Browse the repository at this point in the history
Rather than parse an array/object literal and then pull out the
identifiers, both the array and object literal parsing now detect a
destructuring assignment and use the destructuring expression to make the
parsing consistent.
Fixes #2269
  • Loading branch information
lukeapage authored and jugglinmike committed Jul 25, 2015
1 parent d09a219 commit ae48966
Show file tree
Hide file tree
Showing 3 changed files with 381 additions and 311 deletions.
83 changes: 54 additions & 29 deletions src/jshint.js
Original file line number Diff line number Diff line change
Expand Up @@ -1285,20 +1285,22 @@ var JSHINT = (function() {
state.nameStack.set(state.tokens.prev);
that.right = expression(10);
return that;
} else if (left.id === "[") {
if (state.tokens.curr.left.first) {
state.tokens.curr.left.first.forEach(function(t) {
if (t && t.identifier) {
state.funct["(scope)"].block.modify(t.value, t);
}
} else if (left.id === "{" || left.id === "[") {
if (state.tokens.curr.left.destructAssign) {
state.tokens.curr.left.destructAssign.forEach(function(t) {
state.funct["(scope)"].block.modify(t.id, t.token);
});
} else if (!left.left) {
warning("E031", that);
} else if (left.left.value === "arguments" && !state.isStrict()) {
warning("E031", that);
} else {
if (left.id === "{" || !left.left) {
warning("E031", that);
} else if (left.left.value === "arguments" && !state.isStrict()) {
warning("E031", that);
}
}

state.nameStack.set(left.right);
if (left.id === "[") {
state.nameStack.set(left.right);
}

that.right = expression(10);
return that;
Expand Down Expand Up @@ -2622,8 +2624,9 @@ var JSHINT = (function() {
warning("W119", state.tokens.curr, "array comprehension");
}
return comprehensiveArrayExpression();
} else if (blocktype.isDestAssign && !state.inESNext()) {
warning("W104", state.tokens.curr, "destructuring assignment");
} else if (blocktype.isDestAssign) {
this.destructAssign = destructuringPattern({ openingParsed: true, assignment: true });
return this;
}
var b = state.tokens.curr.line !== startLine(state.tokens.next);
this.first = [];
Expand Down Expand Up @@ -2764,7 +2767,7 @@ var JSHINT = (function() {
var currentParams = [];

if (_.contains(["{", "["], state.tokens.next.id)) {
tokens = destructuringExpression();
tokens = destructuringPattern();
for (t in tokens) {
t = tokens[t];
if (t.id) {
Expand Down Expand Up @@ -3122,6 +3125,12 @@ var JSHINT = (function() {
}
}

var blocktype = lookupBlockType();
if (blocktype.isDestAssign) {
this.destructAssign = destructuringPattern({ openingParsed: true, assignment: true });
return this;
}

for (;;) {
if (state.tokens.next.id === "}") {
break;
Expand Down Expand Up @@ -3232,16 +3241,27 @@ var JSHINT = (function() {
};
}(delim("{")));

function destructuringExpression() {
var ids;
var identifiers = [];
function destructuringPattern(options) {
var isAssignment = options && options.assignment;

if (!state.inESNext()) {
warning("W104", state.tokens.curr, "destructuring expression");
warning("W104", state.tokens.curr,
isAssignment ? "destructuring assignment" : "destructuring binding");
}

return destructuringPatternRecursive(options);
}

function destructuringPatternRecursive(options) {
var ids;
var identifiers = [];
var openingParsed = options && options.openingParsed;
var firstToken = openingParsed ? state.tokens.curr : state.tokens.next;

var nextInnerDE = function() {
var ident;
if (checkPunctuators(state.tokens.next, ["[", "{"])) {
ids = destructuringExpression();
ids = destructuringPatternRecursive();
for (var id in ids) {
id = ids[id];
identifiers.push({ id: id.id, token: id.token });
Expand Down Expand Up @@ -3284,8 +3304,10 @@ var JSHINT = (function() {
}
}
};
if (checkPunctuators(state.tokens.next, ["["])) {
advance("[");
if (checkPunctuators(firstToken, ["["])) {
if (!openingParsed) {
advance("[");
}
if (checkPunctuators(state.tokens.next, ["]"])) {
warning("W137", state.tokens.curr);
}
Expand All @@ -3312,8 +3334,11 @@ var JSHINT = (function() {
}
}
advance("]");
} else if (checkPunctuators(state.tokens.next, ["{"])) {
advance("{");
} else if (checkPunctuators(firstToken, ["{"])) {

if (!openingParsed) {
advance("{");
}
if (checkPunctuators(state.tokens.next, ["}"])) {
warning("W137", state.tokens.curr);
}
Expand All @@ -3340,7 +3365,7 @@ var JSHINT = (function() {
return identifiers;
}

function destructuringExpressionMatch(tokens, value) {
function destructuringPatternMatch(tokens, value) {
var first = value.first;

if (!first)
Expand Down Expand Up @@ -3385,7 +3410,7 @@ var JSHINT = (function() {
for (;;) {
var names = [];
if (_.contains(["{", "["], state.tokens.next.value)) {
tokens = destructuringExpression();
tokens = destructuringPattern();
lone = false;
} else {
tokens = [ { id: identifier(), token: state.tokens.curr } ];
Expand All @@ -3411,7 +3436,7 @@ var JSHINT = (function() {
if (lone) {
tokens[0].first = value;
} else {
destructuringExpressionMatch(names, value);
destructuringPatternMatch(names, value);
}
}

Expand Down Expand Up @@ -3476,7 +3501,7 @@ var JSHINT = (function() {
for (;;) {
var names = [];
if (_.contains(["{", "["], state.tokens.next.value)) {
tokens = destructuringExpression();
tokens = destructuringPattern();
lone = false;
} else {
tokens = [ { id: identifier(), token: state.tokens.curr } ];
Expand Down Expand Up @@ -3510,7 +3535,7 @@ var JSHINT = (function() {
if (lone) {
tokens[0].first = value;
} else {
destructuringExpressionMatch(names, value);
destructuringPatternMatch(names, value);
}
}

Expand Down Expand Up @@ -3831,7 +3856,7 @@ var JSHINT = (function() {
state.funct["(scope)"].stackParams();

if (checkPunctuators(state.tokens.next, ["[", "{"])) {
var tokens = destructuringExpression();
var tokens = destructuringPattern();
_.each(tokens, function(token) {
if (token.id) {
state.funct["(scope)"].addParam(token.id, token, "exception");
Expand Down
19 changes: 13 additions & 6 deletions src/scope-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,22 @@ var scopeManager = function(state, predefined, exported, declared) {
});
}

function _addUsage(labelName, token) {
if (token) {
token["(function)"] = _currentFunct;
}
function _setupUsages(labelName) {
if (!_current["(usages)"][labelName]) {
_current["(usages)"][labelName] = {
"(modified)": [],
"(reassigned)": [],
"(tokens)": token ? [token] : []
"(tokens)": []
};
} else if (token) {
}
}

function _addUsage(labelName, token) {

_setupUsages(labelName);

if (token) {
token["(function)"] = _currentFunct;
_current["(usages)"][labelName]["(tokens)"].push(token);
}
}
Expand Down Expand Up @@ -763,6 +768,8 @@ var scopeManager = function(state, predefined, exported, declared) {

modify: function(labelName, token) {

_setupUsages(labelName);

_current["(usages)"][labelName]["(modified)"].push(token);
},

Expand Down

0 comments on commit ae48966

Please sign in to comment.