Skip to content

Commit 1e9c371

Browse files
committed
fix #328: properly suppress default when looking at * exports. (#332)
* fix #328: properly suppress `default` when looking at * exports. * damnnnn, curly. back at it again with indented blocks
1 parent e049817 commit 1e9c371

File tree

10 files changed

+85
-30
lines changed

10 files changed

+85
-30
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44
This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com).
55

6+
## [Unreleased]
7+
### Fixed
8+
- `export * from 'foo'` now properly ignores a `default` export from `foo`, if any. ([#328]/[#332], thanks [@jkimbo])
9+
This impacts all static analysis of imported names. ([`default`], [`named`], [`namespace`], [`export`])
10+
611
## [1.8.0] - 2016-05-11
712
### Added
813
- [`prefer-default-export`], new rule. ([#308], thanks [@gavriguy])
@@ -206,10 +211,13 @@ for info on changes for earlier releases.
206211
[`no-nodejs-modules`]: ./docs/rules/no-nodejs-modules.md
207212
[`order`]: ./docs/rules/order.md
208213
[`named`]: ./docs/rules/named.md
214+
[`default`]: ./docs/rules/default.md
215+
[`export`]: ./docs/rules/export.md
209216
[`newline-after-import`]: ./docs/rules/newline-after-import.md
210217
[`no-mutable-exports`]: ./docs/rules/no-mutable-exports.md
211218
[`prefer-default-export`]: ./docs/rules/prefer-default-export.md
212219

220+
[#332]: https://github.com/benmosher/eslint-plugin-import/pull/332
213221
[#322]: https://github.com/benmosher/eslint-plugin-import/pull/322
214222
[#316]: https://github.com/benmosher/eslint-plugin-import/pull/316
215223
[#308]: https://github.com/benmosher/eslint-plugin-import/pull/308
@@ -235,6 +243,7 @@ for info on changes for earlier releases.
235243
[#164]: https://github.com/benmosher/eslint-plugin-import/pull/164
236244
[#157]: https://github.com/benmosher/eslint-plugin-import/pull/157
237245

246+
[#328]: https://github.com/benmosher/eslint-plugin-import/issues/328
238247
[#317]: https://github.com/benmosher/eslint-plugin-import/issues/317
239248
[#286]: https://github.com/benmosher/eslint-plugin-import/issues/286
240249
[#281]: https://github.com/benmosher/eslint-plugin-import/issues/281
@@ -290,3 +299,4 @@ for info on changes for earlier releases.
290299
[@josh]: https://github.com/josh
291300
[@borisyankov]: https://github.com/borisyankov
292301
[@gavriguy]: https://github.com/gavriguy
302+
[@jkimbo]: https://github.com/jkimbo

src/core/getExports.js

+34-24
Original file line numberDiff line numberDiff line change
@@ -228,13 +228,16 @@ export default class ExportMap {
228228
if (this.namespace.has(name)) return true
229229
if (this.reexports.has(name)) return true
230230

231-
for (let dep of this.dependencies.values()) {
232-
let innerMap = dep()
231+
// default exports must be explicitly re-exported (#328)
232+
if (name !== 'default') {
233+
for (let dep of this.dependencies.values()) {
234+
let innerMap = dep()
233235

234-
// todo: report as unresolved?
235-
if (!innerMap) continue
236+
// todo: report as unresolved?
237+
if (!innerMap) continue
236238

237-
if (innerMap.has(name)) return true
239+
if (innerMap.has(name)) return true
240+
}
238241
}
239242

240243
return false
@@ -264,18 +267,22 @@ export default class ExportMap {
264267
return deep
265268
}
266269

267-
for (let dep of this.dependencies.values()) {
268-
let innerMap = dep()
269-
// todo: report as unresolved?
270-
if (!innerMap) continue
271270

272-
// safeguard against cycles
273-
if (innerMap.path === this.path) continue
271+
// default exports must be explicitly re-exported (#328)
272+
if (name !== 'default') {
273+
for (let dep of this.dependencies.values()) {
274+
let innerMap = dep()
275+
// todo: report as unresolved?
276+
if (!innerMap) continue
277+
278+
// safeguard against cycles
279+
if (innerMap.path === this.path) continue
274280

275-
let innerValue = innerMap.hasDeep(name)
276-
if (innerValue.found) {
277-
innerValue.path.unshift(this)
278-
return innerValue
281+
let innerValue = innerMap.hasDeep(name)
282+
if (innerValue.found) {
283+
innerValue.path.unshift(this)
284+
return innerValue
285+
}
279286
}
280287
}
281288

@@ -298,16 +305,19 @@ export default class ExportMap {
298305
return imported.get(local)
299306
}
300307

301-
for (let dep of this.dependencies.values()) {
302-
let innerMap = dep()
303-
// todo: report as unresolved?
304-
if (!innerMap) continue
308+
// default exports must be explicitly re-exported (#328)
309+
if (name !== 'default') {
310+
for (let dep of this.dependencies.values()) {
311+
let innerMap = dep()
312+
// todo: report as unresolved?
313+
if (!innerMap) continue
305314

306-
// safeguard against cycles
307-
if (innerMap.path === this.path) continue
315+
// safeguard against cycles
316+
if (innerMap.path === this.path) continue
308317

309-
let innerValue = innerMap.get(name)
310-
if (innerValue !== undefined) return innerValue
318+
let innerValue = innerMap.get(name)
319+
if (innerValue !== undefined) return innerValue
320+
}
311321
}
312322

313323
return undefined
@@ -321,7 +331,7 @@ export default class ExportMap {
321331
callback.call(thisArg, getImport().get(local), name, this))
322332

323333
this.dependencies.forEach(dep => dep().forEach((v, n) =>
324-
callback.call(thisArg, v, n, this)))
334+
n !== 'default' && callback.call(thisArg, v, n, this)))
325335
}
326336

327337
// todo: keys, values, entries?

src/rules/export.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ module.exports = function (context) {
5050
return
5151
}
5252
let any = false
53-
remoteExports.forEach((v, name) => (any = true) && addNamed(name, node))
53+
remoteExports.forEach((v, name) =>
54+
name !== 'default' &&
55+
(any = true) && // poor man's filter
56+
addNamed(name, node))
5457

5558
if (!any) {
5659
context.report(node.source,

tests/files/deep-es7/b.js

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * as c from './c'
2+
export default 'b'

tests/files/deep/b.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
import * as c from './c'
2-
export { c }
2+
export { c }
3+
export default 'b'

tests/files/re-export.js

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
export const c = 'foo'
22

33
export * from './named-exports'
4+
5+
// #328: this exports only 'foo', not the default.
6+
export * from './bar'

tests/src/rules/default.js

+6
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,11 @@ ruleTester.run('default', rule, {
115115
parser: 'babel-eslint',
116116
errors: ['No default export found in module.'],
117117
}),
118+
119+
// #328: * exports do not include default
120+
test({
121+
code: 'import barDefault from "./re-export"',
122+
errors: [`No default export found in module.`],
123+
}),
118124
],
119125
})

tests/src/rules/export.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ ruleTester.run('export', rule, {
2121
test({ code: 'export { bar }; export * from "./export-all"' }),
2222
test({ code: 'export * from "./export-all"' }),
2323
test({ code: 'export * from "./does-not-exist"' }),
24+
25+
// #328: "export * from" does not export a default
26+
test({ code: 'export default foo; export * from "./bar"' }),
2427
],
2528

2629
invalid: [
@@ -29,10 +32,6 @@ ruleTester.run('export', rule, {
2932
code: 'export default foo; export default bar',
3033
errors: ['Multiple default exports.', 'Multiple default exports.'],
3134
}),
32-
test({
33-
code: 'export default foo; export * from "./default-export"',
34-
errors: ['Multiple default exports.', 'Multiple default exports.'],
35-
}),
3635
test({
3736
code: 'export default function foo() {}; ' +
3837
'export default function bar() {}',
@@ -99,5 +98,11 @@ ruleTester.run('export', rule, {
9998
'Multiple exports of name \'bar\'.'],
10099
}),
101100

101+
102+
// #328: "export * from" does not export a default
103+
test({
104+
code: 'export * from "./default-export"',
105+
errors: [`No named exports found in module './default-export'.`],
106+
}),
102107
],
103108
})

tests/src/rules/named.js

+6
Original file line numberDiff line numberDiff line change
@@ -217,5 +217,11 @@ ruleTester.run('named', rule, {
217217
// todo: better error message
218218
errors: ["common not found via re-export-default.js -> common.js"],
219219
}),
220+
221+
// #328: * exports do not include default
222+
test({
223+
code: 'import { default as barDefault } from "./re-export"',
224+
errors: [`default not found in './re-export'`],
225+
}),
220226
],
221227
})

tests/src/rules/namespace.js

+10
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ const valid = [
7777

7878
// names.default is valid export
7979
test({ code: "import * as names from './default-export';" }),
80+
test({ code: "import * as names from './default-export'; console.log(names.default)" }),
8081
test({
8182
code: 'export * as names from "./default-export"',
8283
parser: 'babel-eslint',
@@ -164,6 +165,12 @@ const invalid = [
164165
errors: [error('c', 'names')],
165166
}),
166167

168+
// #328: * exports do not include default
169+
test({
170+
code: 'import * as ree from "./re-export"; console.log(ree.default)',
171+
errors: [`'default' not found in imported namespace 'ree'.`],
172+
}),
173+
167174
]
168175

169176
///////////////////////
@@ -177,6 +184,9 @@ const invalid = [
177184
test({ parser, code: `import * as a from "./${folder}/a"; var {b:{c:{d:{e}}}} = a` }),
178185
test({ parser, code: `import { b } from "./${folder}/a"; var {c:{d:{e}}} = b` }))
179186

187+
// deep namespaces should include explicitly exported defaults
188+
test({ parser, code: `import * as a from "./${folder}/a"; console.log(a.b.default)` }),
189+
180190
invalid.push(
181191
test({
182192
parser,

0 commit comments

Comments
 (0)