-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
172 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import minimatch from 'minimatch' | ||
import path from 'path' | ||
import readPkgUp from 'read-pkg-up' | ||
|
||
function getEntryPoint(context) { | ||
try { | ||
const pkg = readPkgUp.sync({cwd: context.getFilename(), normalize: false}) | ||
return pkg && pkg.pkg | ||
? path.join(process.cwd(), pkg.pkg.main) | ||
: null | ||
} catch (e) { | ||
return null | ||
} | ||
} | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: 'Disallow import statements with module.exports', | ||
category: 'Best Practices', | ||
recommended: true, | ||
}, | ||
fixable: 'code', | ||
schema: [ | ||
{ | ||
'type': 'object', | ||
'properties': { | ||
'exceptions': { 'type': 'array' }, | ||
}, | ||
'additionalProperties': false, | ||
}, | ||
], | ||
}, | ||
create(context) { | ||
const importDeclarations = [] | ||
const entryPoint = getEntryPoint(context) | ||
const options = context.options[0] || {} | ||
let alreadyReported = false | ||
|
||
function report(node) { | ||
const fileName = context.getFilename() | ||
const isEntryPoint = entryPoint === fileName | ||
const isIdentifier = node.object.type === 'Identifier' | ||
const hasKeywords = (/^(module|exports)$/).test(node.object.name) | ||
const isException = options.exceptions | ||
? options.exceptions.some(glob => minimatch(fileName, glob)) | ||
: false | ||
|
||
if (isIdentifier && hasKeywords && !isEntryPoint && !isException) { | ||
importDeclarations.forEach(importDeclaration => { | ||
context.report({ | ||
node: importDeclaration, | ||
message: `Cannot use import declarations in modules that export using ` + | ||
`CommonJS (module.exports = 'foo' or exports.bar = 'hi')`, | ||
}) | ||
}) | ||
alreadyReported = true | ||
} | ||
} | ||
|
||
return { | ||
ImportDeclaration(node) { | ||
importDeclarations.push(node) | ||
}, | ||
MemberExpression(node) { | ||
if (!alreadyReported) { | ||
report(node) | ||
} | ||
}, | ||
} | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
{ | ||
"dummy": true, | ||
"main": "tests/files/lib/main.js", | ||
"devDependencies": { | ||
"glob": "1.0.0", | ||
"eslint": "2.x" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import path from 'path' | ||
import { RuleTester } from 'eslint' | ||
|
||
import { test, testFilePath } from '../utils' | ||
|
||
const ruleTester = new RuleTester({ | ||
parserOptions: { ecmaVersion: 6, sourceType: 'module' } | ||
}) | ||
const rule = require('rules/no-import-module-exports') | ||
|
||
const error = { | ||
message: `Cannot use import declarations in modules that export using CommonJS ` + | ||
`(module.exports = 'foo' or exports.bar = 'hi')`, | ||
type: 'ImportDeclaration', | ||
} | ||
|
||
ruleTester.run('no-import-module-exports', rule, { | ||
valid: [ | ||
test({ | ||
code: ` | ||
const thing = require('thing') | ||
module.exports = thing | ||
`, | ||
}), | ||
test({ | ||
code: ` | ||
import thing from 'otherthing' | ||
console.log(thing.module.exports) | ||
`, | ||
}), | ||
test({ | ||
code: ` | ||
import thing from 'other-thing' | ||
export default thing | ||
`, | ||
}), | ||
test({ | ||
code: ` | ||
import foo from 'path'; | ||
module.exports = foo; | ||
`, | ||
// When the file matches the entry point defined in package.json | ||
// See tests/files/package.json | ||
filename: path.join(process.cwd(), 'tests/files/lib/main.js'), | ||
}), | ||
test({ | ||
code: ` | ||
import foo from 'path'; | ||
module.exports = foo; | ||
`, | ||
filename: path.join(process.cwd(), 'tests/files/some/other/entry-point.js'), | ||
options: [{ exceptions: ['**/*/other/entry-point.js'] }], | ||
}), | ||
], | ||
invalid: [ | ||
test({ | ||
code: ` | ||
import { stuff } from 'starwars' | ||
module.exports = thing | ||
`, | ||
errors: [error], | ||
}), | ||
test({ | ||
code: ` | ||
import thing from 'starwars' | ||
const baz = module.exports = thing | ||
console.log(baz) | ||
`, | ||
errors: [error], | ||
}), | ||
test({ | ||
code: ` | ||
import * as allThings from 'starwars' | ||
exports.bar = thing | ||
`, | ||
errors: [error], | ||
}), | ||
test({ | ||
code: ` | ||
import foo from 'path'; | ||
module.exports = foo; | ||
`, | ||
// When the file does not match the entry point defined in package.json | ||
// See tests/files/package.json | ||
filename: path.join(process.cwd(), 'tests/files/not/lib/main.js'), | ||
errors: [error], | ||
}), | ||
test({ | ||
code: ` | ||
import foo from 'path'; | ||
module.exports = foo; | ||
`, | ||
filename: path.join(process.cwd(), 'tests/files/some/other/entry-point.js'), | ||
options: [{ exceptions: ['**/*/other/file.js'] }], | ||
errors: [error], | ||
}), | ||
], | ||
}) |