Skip to content

Commit

Permalink
New: Implement no-assign-exports rule (fixes #6)
Browse files Browse the repository at this point in the history
  • Loading branch information
Casey Visco committed Apr 9, 2015
1 parent 8520870 commit 03c7e6d
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -52,6 +52,7 @@ Enable the rules that you would like to use, for example:
* [no-amd-define](docs/rules/no-amd-define.md): Disallow AMD (dependency array) form of `define` (off by default)
* [no-named-define](docs/rules/no-named-define.md): Disallow named module form of `define` (off by default)
* [no-commonjs-wrapper](docs/rules/no-commonjs-wrapper.md): Disallow use of Simplified CommonJS Wrapper (off by default)
* [no-assign-exports](docs/rules/no-assign-exports.md): Disallow assignment to `exports` when using Simplified CommonJS Wrapper

### Don't see the rule you're looking for?

Expand Down
37 changes: 37 additions & 0 deletions docs/rules/no-assign-exports.md
@@ -0,0 +1,37 @@
# Disallow assignment to `exports` when using Simplified CommonJS Wrapper (no-assign-exports)

## Rule Details

This rule aims to prevent assignment to the `exports` variable. This is generally an error, as assignment should be done to `module.exports` instead. This rule is only in effect when using the Simplified CommonJS Wrapper.

The following patterns are considered warnings:

```js
define(function (require, exports) {
exports = function () {
/* ... */
};
});

define(function (require, exports) {
exports = {
doSomething: function () {
/* ... */
}
};
});
```

The following patterns are not warnings:

```js
define(function (require, exports) {
exports.doSomething: function () {
/* ... */
};
});
```

## When Not To Use It

You should probably *not* disable this rule.
4 changes: 3 additions & 1 deletion index.js
Expand Up @@ -8,13 +8,15 @@ module.exports = {
"no-function-define": require("./lib/rules/no-function-define"),
"no-amd-define": require("./lib/rules/no-amd-define"),
"no-named-define": require("./lib/rules/no-named-define"),
"no-commonjs-wrapper": require("./lib/rules/no-commonjs-wrapper")
"no-commonjs-wrapper": require("./lib/rules/no-commonjs-wrapper"),
"no-assign-exports": require("./lib/rules/no-assign-exports")
},
rulesConfig: {

// Potential Errors
"no-invalid-define": 2,
"no-multiple-define": 2,
"no-assign-exports": 2,

// Stylistic Choices
"no-object-define": 0,
Expand Down
49 changes: 49 additions & 0 deletions lib/rules/no-assign-exports.js
@@ -0,0 +1,49 @@
/**
* @fileoverview Disallow assignment to `exports` when using Simplified CommonJS Wrapper
* @author Casey Visco
*/

"use strict";

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

var helpers = require("../helpers");


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

module.exports = function (context) {

var isCommonJS = false;

//------------------------------------------------------------------------------
// Public
//------------------------------------------------------------------------------

return {
"CallExpression": function (node) {
isCommonJS = isCommonJS || helpers.isCommonJsDef(node.arguments);
},

"CallExpression:exit": function (node) {
if (helpers.isCommonJsDef(node.arguments)) {
isCommonJS = false;
}
},

"AssignmentExpression": function (node) {
var isIdentifier = node.left.type === "Identifier",
isExports = node.left.name === "exports";

if (isCommonJS && isIdentifier && isExports) {
context.report(node, "Invalid assignment to `exports`.");
}
}
};

};

11 changes: 11 additions & 0 deletions tests/lib/fixtures.js
Expand Up @@ -19,5 +19,16 @@ module.exports = {
AMD_NAMED: "define('path/to/c', ['path/to/a', 'path/to/b'], function (a, b) { return true; });",
AMD_NAMED_EMPTY: "define('path/to/c', [], function () { return true; });"

},

exports: {

// Always Invalid
ASSIGN_EXPORTS: "define(function (require, exports) { exports = { foo: 'bar' }; });",

// Valid unless disabled
MODIFY_EXPORTS: "define(function (require, exports) { exports.foo = 'bar'; });",
ASSIGN_MODULE_EXPORTS: "define(function (require, exports, module) { module.exports = { foo: 'bar' }; });",
NO_CJS_ASSIGN_EXPORTS: "exports = { foo: 'bar' };"
}
};
41 changes: 41 additions & 0 deletions tests/lib/rules/no-assign-exports.js
@@ -0,0 +1,41 @@
/**
* @fileoverview Tests for `no-assign-exports` rule
* @author Casey Visco <cvisco@gmail.com>
*/

"use strict";

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

var eslint = require("eslint"),
ESLintTester = require("eslint-tester"),
fixtures = require("../fixtures");


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

var eslintTester = new ESLintTester(eslint.linter);

eslintTester.addRuleTest("lib/rules/no-assign-exports", {

valid: [
fixtures.exports.MODIFY_EXPORTS,
fixtures.exports.ASSIGN_MODULE_EXPORTS,
fixtures.exports.NO_CJS_ASSIGN_EXPORTS
],

invalid: [
{
code: fixtures.exports.ASSIGN_EXPORTS,
errors: [{
message: "Invalid assignment to `exports`.",
type: "AssignmentExpression"
}]
}
]

});

0 comments on commit 03c7e6d

Please sign in to comment.