[New] Add no-import-module-exports rule#804
Conversation
… with CommonJS exports Fixes import-js#760
ljharb
left a comment
There was a problem hiding this comment.
Could we also handle assignments to the exports object? Like exports.foo = bar
|
@ljharb test({
code: `
import thing from 'other-thing'
exports.foo = bar
`,
errors: [error],
})and the following would be valid: test({
code: `
const thing = require('thing')
exports.foo = bar
`,
}), |
|
Yes, exactly |
| import readPkgUp from 'read-pkg-up' | ||
|
|
||
| function getEntryPoint(context) { | ||
| try { |
There was a problem hiding this comment.
I'm wondering if it'd be easier to just use require.resolve(pathToPackageJSON) here, which reads "main" for you?
There was a problem hiding this comment.
hmm...I'm not sure I follow.
From what I understand require.resolve gives you the absolute path to a given module.
So if I wanted the path to minimatch's package.json I could do:
require.resolve('minimatch/package.json')But I can't use it to get an absolute path to the current module's package.json...Or can I?
By the way, I borrowed this approach from no-extraneous-dependencies. If we come up with a better solution, it might not be a bad idea to implement it there as well.
There was a problem hiding this comment.
If you require.resolve a dir path that contains a package.json, it gives you the path to the "main"
There was a problem hiding this comment.
I'm suggesting finding the package.json first, and then resolving that dir. Not sure if it will work or not here.
There was a problem hiding this comment.
I see what you mean, let me take a looksee
There was a problem hiding this comment.
The require.resolve approach seems to work well. The only thing to take into consideration is the use of read-pkg-up for finding the path to the nearest package.json. Using read-pkg-up the implementation would look something like:
import path from 'path'
import readPkgUp from 'read-pkg-up'
function getEntryPoint(context) {
const pkg = readPkgUp.sync({ cwd: context.getFilename() })
return require.resolve(path.dirname(pkg.path))
}But since all we need is the path to the nearest package.json (we don't actually need to parse it) we could use the pkg-up lib instead. In which case the implementation would look like:
import path from 'path'
import pkgUp from 'pkg-up'
function getEntryPoint(context) {
const pkgPath = pkgUp.sync(context.getFilename())
return require.resolve(path.dirname(pkgPath))
}So, we can:
A) Stick to the current implementation where we parse the package.json, and create the path to "main" ourselves.
B) Use read-pkg-up to find the path to the nearest package.json, then use require.resolve to get the path to main.
C) Install and use pkg-up to find the path to the nearest package.json, then use require.resolve to get the path to main.
I prefer B and C over A....and lean towards C, but I'm not sure what the cost would be of adding another dependency. What do you think?
There was a problem hiding this comment.
pkg-up is already a dep of read-pkg-up, and the cost of adding dependencies to a dev dependency is virtually zero. I'd say C.
However, I just realized my comment on the original issue does also add that it should probably support jsnext:main, and for that, you'd need A or B.
I'd still lean towards C for the primary case.
There was a problem hiding this comment.
C it is. Here's the diff.
Those using jsnext:main can always add their second entry to the exceptions in the rule options. I will add something to that effect in the docs.
| 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)) |
There was a problem hiding this comment.
this could be options.exceptions && options.exceptions.some(…), but this is fine too :-)
|
|
||
| ```json | ||
| "import/no-import-module-exports": ["error", { | ||
| "exceptions": ['**/*/some-file.js'] |
| module.exports = foo; | ||
|
|
||
| /* in some-file.js */ | ||
| /* eslint import/no-import-module-exports: ["error", {"exceptions": ['**/*/some-file.js']}] */ |
There was a problem hiding this comment.
these should also probably be double quotes, but also, the */ actually does end the comment, so this should probably be a // comment :-)
| errors: [error], | ||
| }), | ||
| test({ | ||
| code: ` |
There was a problem hiding this comment.
Ahh....the four tests above this one are already testing that the rule applies for files that aren't "main". By default the test util sets the default file to eslint-plugin-import/tests/files/foo.js. Which isn't equal to the "main" I set up in eslint-plugin-import/tests/files/package.json. It seemed a bit redundant to me...but I can add it back if you prefer.
|
@benmosher @jfmengels any thoughts? |
|
🎵 all I want for christmaaas 🎵... is for this to be merged. 🎅 |
6e8f406 to
86bbf94
Compare
1b407b9 to
a45661b
Compare
no-import-module-exports rule
Fixes #760
Still a work in progress.
Updates to the changelog and docs to follow.