Skip to content

Commit

Permalink
New: no-sloppy-block-bindings rule (fixes #6)
Browse files Browse the repository at this point in the history
  • Loading branch information
mysticatea committed Dec 15, 2015
1 parent 0cd0623 commit ca2c7bb
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Some rules are slow because it searches `package.json` and opens it.
"rules": {
"node/no-missing-import": 2,
"node/no-missing-require": 2,
"node/no-sloppy-block-bindings": 2,
"node/shebang": 2
}
}
Expand All @@ -36,4 +37,5 @@ Some rules are slow because it searches `package.json` and opens it.

- [no-missing-import](docs/rules/no-missing-import.md) - Disallow invalid `import` and `export` declarations.
- [no-missing-require](docs/rules/no-missing-require.md) - Disallow invalid `require()`s.
- [no-sloppy-block-bindings](docs/rules/no-sloppy-block-bindings.md) - Disallow block-scoped declarations outside strict mode.
- [shebang](docs/rules/shebang.md) - Suggest correct usage of shebang.
54 changes: 54 additions & 0 deletions docs/rules/no-sloppy-block-bindings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Disallow block-scoped declarations outside strict mode (no-sloppy-block-bindings)

Node.js 5.x or before don't support block-scoped declarations outside strict mode.

```
$ node -e "let a = 0;"
[eval]:1
let a = 0;
^^^
SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
at Object.exports.runInThisContext (vm.js:54:16)
at Object.<anonymous> ([eval]-wrapper:6:22)
at Module._compile (module.js:399:26)
at node.js:592:27
at nextTickCallbackWith0Args (node.js:433:9)
at process._tickCallback (node.js:362:13)
```

## Rule Details

This rule finds block-scoped declarations outside strict mode, then warns these.

The following patterns are considered problems:

```js
let a = 0; /*error Block-scoped declarations (let, const, function, class) not yet supported outside strict mode.*/
const b = 0; /*error Block-scoped declarations (let, const, function, class) not yet supported outside strict mode.*/
class C {} /*error Block-scoped declarations (let, const, function, class) not yet supported outside strict mode.*/

if (a) {
function d() {} /*error Block-scoped declarations (let, const, function, class) not yet supported outside strict mode.*/
}
```

The following patterns are considered not problems:

```js
"use strict";

let a = 0;
const b = 0;
class C {}

if (a) {
function d() {}
}
```

**Node:** In modules, the program is always strict mode.

## When Not To Use It

If you don't want to notify about block-scoped declarations, then it's safe to disable this rule.
54 changes: 54 additions & 0 deletions lib/rules/no-sloppy-block-bindings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* @fileoverview Rule to disallow block-scoped declarations outside strict mode.
* @author Toru Nagashima
* @copyright 2015 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
*/

"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function(context) {
/**
* Reports a given node if it's in sloppy mode.
* @param {ASTNode} node - A node to report.
* @returns {void}
*/
function reportIfInSloppy(node) {
var scope = context.getScope();
if (!scope.isStrict) {
context.report({
message: "Block-scoped declarations (let, const, function, class) not yet supported outside strict mode.",
node: node
});
}
}

// In modules, all are OK.
if ((context.parserOptions && context.parserOptions.sourceType === "module") ||
(context.ecmaFeatures && context.ecmaFeatures.modules)
) {
return {};
}

return {
ClassDeclaration: reportIfInSloppy,
ClassExpression: reportIfInSloppy,
FunctionDeclaration: function(node) {
var scope = context.getScope().upper;
if (scope.type !== "global" && scope.type !== "function") {
reportIfInSloppy(node);
}
},
VariableDeclaration: function(node) {
if (node.kind === "let" || node.kind === "const") {
reportIfInSloppy(node);
}
}
};
};

module.exports.schema = [];
54 changes: 54 additions & 0 deletions tests/lib/rules/no-sloppy-block-bindings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* @fileoverview Tests for no-sloppy-block-bindings rule.
* @author Toru Nagashima
* @copyright 2015 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
*/

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

var rule = require("../../../lib/rules/no-sloppy-block-bindings"),
RuleTester = require("eslint").RuleTester;

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

var ruleTester = new RuleTester();
ruleTester.run("no-sloppy-block-bindings", rule, {
valid: [
{code: "var a;"},
{code: "function foo(a) { function foo() {} }"},
{code: "'use strict'; let a;", env: {es6: true}},
{code: "'use strict'; const a = 0;", env: {es6: true}},
{code: "'use strict'; class A {}", env: {es6: true}},
{code: "'use strict'; if (0) { function foo() {} }", env: {es6: true}},
{code: "'use strict'; function foo() { let a; }", env: {es6: true}},
{code: "'use strict'; function foo() { const a = 0; }", env: {es6: true}},
{code: "'use strict'; function foo() { class A {} }", env: {es6: true}},
{code: "'use strict'; function foo() { if (0) { function foo() {} } }", env: {es6: true}},
{code: "function foo() { 'use strict'; let a; }", env: {es6: true}},
{code: "function foo() { 'use strict'; const a = 0; }", env: {es6: true}},
{code: "function foo() { 'use strict'; class A {} }", env: {es6: true}},
{code: "function foo() { 'use strict'; if (0) { function foo() {} } }", env: {es6: true}},
{code: "let a;", env: {es6: true}, ecmaFeatures: {modules: true}, parserOptions: {sourceType: "module"}},
{code: "const a = 0;", env: {es6: true}, ecmaFeatures: {modules: true}, parserOptions: {sourceType: "module"}},
{code: "class A {}", env: {es6: true}, ecmaFeatures: {modules: true}, parserOptions: {sourceType: "module"}},
{code: "if (0) { function foo() {} }", env: {es6: true}, ecmaFeatures: {modules: true}, parserOptions: {sourceType: "module"}},
{code: "function foo() { let a; }", env: {es6: true}, ecmaFeatures: {modules: true}, parserOptions: {sourceType: "module"}},
{code: "function foo() { const a = 0; }", env: {es6: true}, ecmaFeatures: {modules: true}, parserOptions: {sourceType: "module"}},
{code: "function foo() { class A {} }", env: {es6: true}, ecmaFeatures: {modules: true}, parserOptions: {sourceType: "module"}},
{code: "function foo() { if (0) { function foo() {} } }", env: {es6: true}, ecmaFeatures: {modules: true}, parserOptions: {sourceType: "module"}}
],
invalid: [
{code: "'foo'; let a;", env: {es6: true}, errors: ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode."]},
{code: "'bar'; const a = 0;", env: {es6: true}, errors: ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode."]},
{code: "class A {}", env: {es6: true}, errors: ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode."]},
{code: "if (0) { function foo() {} }", env: {es6: true}, errors: ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode."]},
{code: "try { function foo() {} } catch (e) {}", env: {es6: true}, errors: ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode."]}
]
});

0 comments on commit ca2c7bb

Please sign in to comment.