Skip to content

Commit

Permalink
Update: no-undefined handles properties/classes/modules (fixes #7964)
Browse files Browse the repository at this point in the history
  • Loading branch information
platinumazure committed Feb 7, 2017
1 parent 8ea98f9 commit 58512ac
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 9 deletions.
51 changes: 45 additions & 6 deletions lib/rules/no-undefined.js
Expand Up @@ -21,15 +21,54 @@ module.exports = {

create(context) {

/**
* Report an invalid "undefined" identifier node.
* @param {ASTNode} node The node to report.
* @returns {void}
*/
function report(node) {
context.report({
node,
message: "Unexpected use of undefined."
});
}

/**
* Checks the given scope for references to `undefined` and reports
* all references found.
* @param {escope.Scope} scope The scope to check.
* @returns {void}
*/
function checkScope(scope) {
const undefinedVar = scope.set.get("undefined");

if (!undefinedVar) {
return;
}

const references = undefinedVar.references;

const defs = undefinedVar.defs;

// Report non-initializing references (those are covered in defs below)
references
.filter(ref => !ref.init)
.forEach(ref => report(ref.identifier));

defs.forEach(def => report(def.name));
}

return {
"Program:exit"() {
const globalScope = context.getScope();

const stack = [globalScope];

Identifier(node) {
if (node.name === "undefined") {
const parent = context.getAncestors().pop();
while (stack.length) {
const scope = stack.pop();

if (!parent || parent.type !== "MemberExpression" || node !== parent.property || parent.computed) {
context.report({ node, message: "Unexpected use of undefined." });
}
stack.push.apply(stack, scope.childScopes);
checkScope(scope);
}
}
};
Expand Down
80 changes: 77 additions & 3 deletions tests/lib/rules/no-undefined.js
Expand Up @@ -12,13 +12,20 @@
const rule = require("../../../lib/rules/no-undefined"),
RuleTester = require("../../../lib/testers/rule-tester");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

const ES6_SCRIPT = { ecmaVersion: 6 };
const ES6_MODULE = { ecmaVersion: 6, sourceType: "module" };

//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

const errors = [{ message: "Unexpected use of undefined.", type: "Identifier" }];

const ruleTester = new RuleTester();
const ruleTester = new RuleTester({ parserOptions: ES6_SCRIPT });

ruleTester.run("no-undefined", rule, {
valid: [
Expand All @@ -31,7 +38,18 @@ ruleTester.run("no-undefined", rule, {
"ndefined",
"a.undefined",
"this.undefined",
"global['undefined']"
"global['undefined']",

// https://github.com/eslint/eslint/issues/7964
"({ undefined: bar })",
"({ undefined: bar } = foo)",
"({ undefined() {} })",
"class Foo { undefined() {} }",
"(class { undefined() {} })",
{ code: "import { undefined as a } from 'foo'", parserOptions: ES6_MODULE },
{ code: "export { undefined } from 'foo'", parserOptions: ES6_MODULE },
{ code: "export { undefined as a } from 'foo'", parserOptions: ES6_MODULE },
{ code: "export { a as undefined } from 'foo'", parserOptions: ES6_MODULE }
],
invalid: [
{ code: "undefined", errors },
Expand All @@ -40,10 +58,66 @@ ruleTester.run("no-undefined", rule, {
{ code: "undefined[0]", errors },
{ code: "f(undefined)", errors },
{ code: "function f(undefined) {}", errors },
{ code: "function f() { var undefined; }", errors },
{ code: "function f() { undefined = true; }", errors },
{ code: "var undefined;", errors },
{ code: "try {} catch(undefined) {}", errors },
{ code: "function undefined() {}", errors },
{ code: "(function undefined(){}())", errors },
{ code: "var foo = function undefined() {}", errors },
{ code: "foo = function undefined() {}", errors },
{ code: "undefined = true", errors },
{ code: "var undefined = true", errors }
{ code: "var undefined = true", errors },
{ code: "({ undefined })", errors },
{ code: "({ [undefined]: foo })", errors },
{ code: "({ bar: undefined })", errors },
{ code: "({ bar: undefined } = foo)", errors },
{ code: "var { undefined } = foo", errors },
{ code: "var { bar: undefined } = foo", errors },
{
code: "({ undefined: function undefined() {} })",
errors: [Object.assign({}, errors[0], { column: 24 })]
},
{ code: "({ foo: function undefined() {} })", errors },
{ code: "class Foo { [undefined]() {} }", errors },
{ code: "(class { [undefined]() {} })", errors },
{
code: "var undefined = true; undefined = false;",
errors: [{
message: "Unexpected use of undefined.",
column: 5
}, {
message: "Unexpected use of undefined.",
column: 23
}]
},
{
code: "import undefined from 'foo'",
parserOptions: ES6_MODULE,
errors
},
{
code: "import * as undefined from 'foo'",
parserOptions: ES6_MODULE,
errors
},
{
code: "import { undefined } from 'foo'",
parserOptions: ES6_MODULE,
errors
},
{
code: "import { a as undefined } from 'foo'",
parserOptions: ES6_MODULE,
errors
},
{
code: "export { undefined }",
parserOptions: ES6_MODULE,
errors
},
{ code: "let a = [b, ...undefined]", errors },
{ code: "[a, ...undefined] = b", errors },
{ code: "[a = undefined] = b", errors }
]
});

0 comments on commit 58512ac

Please sign in to comment.