Skip to content

Commit 0b585a1

Browse files
Maxim-Mazurokljharb
authored andcommitted
[New] import/default: support default export in TSExportAssignment
1 parent 0547c7e commit 0b585a1

File tree

8 files changed

+97
-11
lines changed

8 files changed

+97
-11
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
1010
- [`import/default`]: support default export in TSExportAssignment ([#1528], thanks [@joaovieira])
1111
- [`no-cycle`]: add `ignoreExternal` option ([#1681], thanks [@sveyret])
1212
- [`order`]: Add support for TypeScript's "import equals"-expressions ([#1785], thanks [@manuth])
13+
- [`import/default`]: support default export in TSExportAssignment ([#1689], thanks [@Maxim-Mazurok])
1314

1415
### Fixed
1516
- [`group-exports`]: Flow type export awareness ([#1702], thanks [@ernestostifano])
@@ -705,6 +706,7 @@ for info on changes for earlier releases.
705706
[#1702]: https://github.com/benmosher/eslint-plugin-import/issues/1702
706707
[#1691]: https://github.com/benmosher/eslint-plugin-import/pull/1691
707708
[#1690]: https://github.com/benmosher/eslint-plugin-import/pull/1690
709+
[#1689]: https://github.com/benmosher/eslint-plugin-import/pull/1689
708710
[#1681]: https://github.com/benmosher/eslint-plugin-import/pull/1681
709711
[#1676]: https://github.com/benmosher/eslint-plugin-import/pull/1676
710712
[#1666]: https://github.com/benmosher/eslint-plugin-import/pull/1666
@@ -1189,3 +1191,4 @@ for info on changes for earlier releases.
11891191
[@barbogast]: https://github.com/barbogast
11901192
[@adamborowski]: https://github.com/adamborowski
11911193
[@adjerbetian]: https://github.com/adjerbetian
1194+
[@Maxim-Mazurok]: https://github.com/Maxim-Mazurok

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@
108108
"minimatch": "^3.0.4",
109109
"object.values": "^1.1.0",
110110
"read-pkg-up": "^2.0.0",
111-
"resolve": "^1.12.0"
111+
"resolve": "^1.12.0",
112+
"tsconfig-paths": "^3.9.0"
112113
},
113114
"nyc": {
114115
"require": [

src/ExportMap.js

+35-10
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ import isIgnored, { hasValidExtension } from 'eslint-module-utils/ignore'
1313
import { hashObject } from 'eslint-module-utils/hash'
1414
import * as unambiguous from 'eslint-module-utils/unambiguous'
1515

16+
import { tsConfigLoader } from 'tsconfig-paths/lib/tsconfig-loader'
17+
18+
import includes from 'array-includes'
19+
20+
import {parseConfigFileTextToJson} from 'typescript'
21+
1622
const log = debug('eslint-plugin-import:ExportMap')
1723

1824
const exportCache = new Map()
@@ -445,8 +451,23 @@ ExportMap.parse = function (path, content, context) {
445451

446452
const source = makeSourceCode(content, ast)
447453

448-
ast.body.forEach(function (n) {
454+
function isEsModuleInterop() {
455+
const tsConfigInfo = tsConfigLoader({
456+
cwd: context.parserOptions && context.parserOptions.tsconfigRootDir || process.cwd(),
457+
getEnv: (key) => process.env[key],
458+
})
459+
try {
460+
if (tsConfigInfo.tsConfigPath !== undefined) {
461+
const jsonText = fs.readFileSync(tsConfigInfo.tsConfigPath).toString()
462+
const tsConfig = parseConfigFileTextToJson(tsConfigInfo.tsConfigPath, jsonText).config
463+
return tsConfig.compilerOptions.esModuleInterop
464+
}
465+
} catch (e) {
466+
return false
467+
}
468+
}
449469

470+
ast.body.forEach(function (n) {
450471
if (n.type === 'ExportDefaultDeclaration') {
451472
const exportMeta = captureDoc(source, docStyleParsers, n)
452473
if (n.declaration.type === 'Identifier') {
@@ -528,9 +549,14 @@ ExportMap.parse = function (path, content, context) {
528549
})
529550
}
530551

552+
const isEsModuleInteropTrue = isEsModuleInterop()
553+
554+
const exports = ['TSExportAssignment']
555+
isEsModuleInteropTrue && exports.push('TSNamespaceExportDeclaration')
556+
531557
// This doesn't declare anything, but changes what's being exported.
532-
if (n.type === 'TSExportAssignment') {
533-
const exportedName = n.expression.name
558+
if (includes(exports, n.type)) {
559+
const exportedName = n.expression && n.expression.name || n.id.name
534560
const declTypes = [
535561
'VariableDeclaration',
536562
'ClassDeclaration',
@@ -541,18 +567,17 @@ ExportMap.parse = function (path, content, context) {
541567
'TSAbstractClassDeclaration',
542568
'TSModuleDeclaration',
543569
]
544-
const exportedDecls = ast.body.filter(({ type, id, declarations }) =>
545-
declTypes.includes(type) &&
546-
(
547-
(id && id.name === exportedName) ||
548-
(declarations && declarations.find(d => d.id.name === exportedName))
549-
)
550-
)
570+
const exportedDecls = ast.body.filter(({ type, id, declarations }) => includes(declTypes, type) && (
571+
(id && id.name === exportedName) || (declarations && declarations.find((d) => d.id.name === exportedName))
572+
))
551573
if (exportedDecls.length === 0) {
552574
// Export is not referencing any local declaration, must be re-exporting
553575
m.namespace.set('default', captureDoc(source, docStyleParsers, n))
554576
return
555577
}
578+
if (isEsModuleInteropTrue) {
579+
m.namespace.set('default', {})
580+
}
556581
exportedDecls.forEach((decl) => {
557582
if (decl.type === 'TSModuleDeclaration') {
558583
if (decl.body && decl.body.type === 'TSModuleDeclaration') {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export as namespace Foo
2+
3+
export function bar(): void
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"compilerOptions": {
3+
"esModuleInterop": true
4+
}
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export = FooBar;
2+
3+
declare namespace FooBar {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"compilerOptions": {
3+
"esModuleInterop": true
4+
}
5+
}

tests/src/rules/default.js

+41
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import path from 'path'
12
import { test, SYNTAX_CASES, getTSParsers } from '../utils'
23
import { RuleTester } from 'eslint'
34

@@ -189,6 +190,28 @@ context('TypeScript', function () {
189190
'import/resolver': { 'eslint-import-resolver-typescript': true },
190191
},
191192
}),
193+
test({
194+
code: `import React from "./typescript-export-assign-default-namespace"`,
195+
parser: parser,
196+
settings: {
197+
'import/parsers': { [parser]: ['.ts'] },
198+
'import/resolver': { 'eslint-import-resolver-typescript': true },
199+
},
200+
parserOptions: {
201+
tsconfigRootDir: path.resolve(__dirname, '../../files/typescript-export-assign-default-namespace/'),
202+
},
203+
}),
204+
test({
205+
code: `import Foo from "./typescript-export-as-default-namespace"`,
206+
parser: parser,
207+
settings: {
208+
'import/parsers': { [parser]: ['.ts'] },
209+
'import/resolver': { 'eslint-import-resolver-typescript': true },
210+
},
211+
parserOptions: {
212+
tsconfigRootDir: path.resolve(__dirname, '../../files/typescript-export-as-default-namespace/'),
213+
},
214+
}),
192215
],
193216

194217
invalid: [
@@ -201,6 +224,24 @@ context('TypeScript', function () {
201224
},
202225
errors: ['No default export found in imported module "./typescript".'],
203226
}),
227+
test({
228+
code: `import React from "./typescript-export-assign-default-namespace"`,
229+
parser: parser,
230+
settings: {
231+
'import/parsers': { [parser]: ['.ts'] },
232+
'import/resolver': { 'eslint-import-resolver-typescript': true },
233+
},
234+
errors: ['No default export found in imported module "./typescript-export-assign-default-namespace".'],
235+
}),
236+
test({
237+
code: `import FooBar from "./typescript-export-as-default-namespace"`,
238+
parser: parser,
239+
settings: {
240+
'import/parsers': { [parser]: ['.ts'] },
241+
'import/resolver': { 'eslint-import-resolver-typescript': true },
242+
},
243+
errors: ['No default export found in imported module "./typescript-export-as-default-namespace".'],
244+
}),
204245
],
205246
})
206247
})

0 commit comments

Comments
 (0)