Skip to content

Commit 54d86c8

Browse files
vikr01ljharb
authored andcommittedOct 25, 2018
[New] named: add commonjs option
1 parent 7626a14 commit 54d86c8

File tree

3 files changed

+135
-8
lines changed

3 files changed

+135
-8
lines changed
 

‎CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
88

99
### Added
1010
- [`no-dynamic-require`]: add option `esmodule` ([#1223], thanks [@vikr01])
11+
- [`named`]: add `commonjs` option ([#1222], thanks [@vikr01])
1112

1213
### Fixed
1314
- [`no-duplicates`]: ensure autofix avoids excessive newlines ([#2028], thanks [@ertrzyiks])
@@ -891,7 +892,6 @@ for info on changes for earlier releases.
891892
[#1619]: https://github.com/benmosher/eslint-plugin-import/pull/1619
892893
[#1612]: https://github.com/benmosher/eslint-plugin-import/pull/1612
893894
[#1611]: https://github.com/benmosher/eslint-plugin-import/pull/1611
894-
[#1223]: https://github.com/benmosher/eslint-plugin-import/pull/1223
895895
[#1605]: https://github.com/benmosher/eslint-plugin-import/pull/1605
896896
[#1586]: https://github.com/benmosher/eslint-plugin-import/pull/1586
897897
[#1572]: https://github.com/benmosher/eslint-plugin-import/pull/1572
@@ -963,6 +963,8 @@ for info on changes for earlier releases.
963963
[#1235]: https://github.com/benmosher/eslint-plugin-import/pull/1235
964964
[#1234]: https://github.com/benmosher/eslint-plugin-import/pull/1234
965965
[#1232]: https://github.com/benmosher/eslint-plugin-import/pull/1232
966+
[#1223]: https://github.com/benmosher/eslint-plugin-import/pull/1223
967+
[#1222]: https://github.com/benmosher/eslint-plugin-import/pull/1222
966968
[#1218]: https://github.com/benmosher/eslint-plugin-import/pull/1218
967969
[#1176]: https://github.com/benmosher/eslint-plugin-import/pull/1176
968970
[#1163]: https://github.com/benmosher/eslint-plugin-import/pull/1163

‎src/rules/named.js

+73-7
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,22 @@ module.exports = {
88
docs: {
99
url: docsUrl('named'),
1010
},
11-
schema: [],
11+
schema: [
12+
{
13+
type: 'object',
14+
properties: {
15+
commonjs: {
16+
type: 'boolean',
17+
},
18+
},
19+
additionalProperties: false,
20+
},
21+
],
1222
},
1323

1424
create: function (context) {
25+
const options = context.options[0] || {};
26+
1527
function checkSpecifiers(key, type, node) {
1628
// ignore local exports and type imports/exports
1729
if (
@@ -38,12 +50,11 @@ module.exports = {
3850
}
3951

4052
node.specifiers.forEach(function (im) {
41-
if (im.type !== type) {
42-
return;
43-
}
44-
45-
// ignore type imports
46-
if (im.importKind === 'type' || im.importKind === 'typeof') {
53+
if (
54+
im.type !== type
55+
// ignore type imports
56+
|| im.importKind === 'type' || im.importKind === 'typeof'
57+
) {
4758
return;
4859
}
4960

@@ -63,10 +74,65 @@ module.exports = {
6374
});
6475
}
6576

77+
function checkRequire(node) {
78+
if (
79+
!options.commonjs
80+
|| node.type !== 'VariableDeclarator'
81+
// return if it's not an object destructure or it's an empty object destructure
82+
|| !node.id || node.id.type !== 'ObjectPattern' || node.id.properties.length === 0
83+
// return if there is no call expression on the right side
84+
|| !node.init || node.init.type !== 'CallExpression'
85+
) {
86+
return;
87+
}
88+
89+
const call = node.init;
90+
const [source] = call.arguments;
91+
const variableImports = node.id.properties;
92+
const variableExports = Exports.get(source.value, context);
93+
94+
if (
95+
// return if it's not a commonjs require statement
96+
call.callee.type !== 'Identifier' || call.callee.name !== 'require' || call.arguments.length !== 1
97+
// return if it's not a string source
98+
|| source.type !== 'Literal'
99+
|| variableExports == null
100+
) {
101+
return;
102+
}
103+
104+
if (variableExports.errors.length) {
105+
variableExports.reportErrors(context, node);
106+
return;
107+
}
108+
109+
variableImports.forEach(function (im) {
110+
if (im.type !== 'Property' || !im.key || im.key.type !== 'Identifier') {
111+
return;
112+
}
113+
114+
const deepLookup = variableExports.hasDeep(im.key.name);
115+
116+
if (!deepLookup.found) {
117+
if (deepLookup.path.length > 1) {
118+
const deepPath = deepLookup.path
119+
.map(i => path.relative(path.dirname(context.getFilename()), i.path))
120+
.join(' -> ');
121+
122+
context.report(im.key, `${im.key.name} not found via ${deepPath}`);
123+
} else {
124+
context.report(im.key, im.key.name + ' not found in \'' + source.value + '\'');
125+
}
126+
}
127+
});
128+
}
129+
66130
return {
67131
ImportDeclaration: checkSpecifiers.bind(null, 'imported', 'ImportSpecifier'),
68132

69133
ExportNamedDeclaration: checkSpecifiers.bind(null, 'local', 'ExportSpecifier'),
134+
135+
VariableDeclarator: checkRequire,
70136
};
71137
},
72138
};

‎tests/src/rules/named.js

+59
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,41 @@ ruleTester.run('named', rule, {
146146
code: 'import { common } from "./re-export-default"',
147147
}),
148148

149+
// destructured requires with commonjs option
150+
test({
151+
code: 'const { destructuredProp } = require("./named-exports")',
152+
options: [{ commonjs: true }],
153+
}),
154+
test({
155+
code: 'let { arrayKeyProp } = require("./named-exports")',
156+
options: [{ commonjs: true }],
157+
}),
158+
test({
159+
code: 'const { deepProp } = require("./named-exports")',
160+
options: [{ commonjs: true }],
161+
}),
162+
163+
test({
164+
code: 'const { foo, bar } = require("./re-export-names")',
165+
options: [{ commonjs: true }],
166+
}),
167+
168+
test({
169+
code: 'const { baz } = require("./bar")',
170+
errors: [error('baz', './bar')],
171+
}),
172+
173+
test({
174+
code: 'const { baz } = require("./bar")',
175+
errors: [error('baz', './bar')],
176+
options: [{ commonjs: false }],
177+
}),
178+
179+
test({
180+
code: 'const { default: defExport } = require("./bar")',
181+
options: [{ commonjs: true }],
182+
}),
183+
149184
...SYNTAX_CASES,
150185
],
151186

@@ -201,6 +236,30 @@ ruleTester.run('named', rule, {
201236
errors: ['baz not found via broken-trampoline.js -> named-exports.js'],
202237
}),
203238

239+
test({
240+
code: 'const { baz } = require("./bar")',
241+
errors: [error('baz', './bar')],
242+
options: [{ commonjs: true }],
243+
}),
244+
245+
test({
246+
code: 'let { baz } = require("./bar")',
247+
errors: [error('baz', './bar')],
248+
options: [{ commonjs: true }],
249+
}),
250+
251+
test({
252+
code: 'const { baz: bar, bop } = require("./bar"), { a } = require("./re-export-names")',
253+
errors: [error('baz', './bar'), error('bop', './bar'), error('a', './re-export-names')],
254+
options: [{ commonjs: true }],
255+
}),
256+
257+
test({
258+
code: 'const { default: defExport } = require("./named-exports")',
259+
errors: [error('default', './named-exports')],
260+
options: [{ commonjs: true }],
261+
}),
262+
204263
// parse errors
205264
// test({
206265
// code: "import { a } from './test.coffee';",

0 commit comments

Comments
 (0)
Please sign in to comment.