diff --git a/CHANGELOG.md b/CHANGELOG.md index ea4eebef6..f88d03d69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ## [Unreleased] +### Added +- [`import/default`]: support default export in TSExportAssignment ([#1528], thanks [@joaovieira]) + ### Fixed - [`group-exports`]: Flow type export awareness ([#1702], thanks [@ernestostifano]) - [`order`]: Recognize pathGroup config for first group ([#1719], [#1724], thanks [@forivall], [@xpl]) @@ -697,6 +700,7 @@ for info on changes for earlier releases. [#1560]: https://github.com/benmosher/eslint-plugin-import/pull/1560 [#1551]: https://github.com/benmosher/eslint-plugin-import/pull/1551 [#1542]: https://github.com/benmosher/eslint-plugin-import/pull/1542 +[#1528]: https://github.com/benmosher/eslint-plugin-import/pull/1528 [#1526]: https://github.com/benmosher/eslint-plugin-import/pull/1526 [#1521]: https://github.com/benmosher/eslint-plugin-import/pull/1521 [#1519]: https://github.com/benmosher/eslint-plugin-import/pull/1519 diff --git a/src/ExportMap.js b/src/ExportMap.js index 525f64a48..5a36b220b 100644 --- a/src/ExportMap.js +++ b/src/ExportMap.js @@ -530,30 +530,50 @@ ExportMap.parse = function (path, content, context) { // This doesn't declare anything, but changes what's being exported. if (n.type === 'TSExportAssignment') { - const moduleDecls = ast.body.filter((bodyNode) => - bodyNode.type === 'TSModuleDeclaration' && bodyNode.id.name === n.expression.name + const exportedName = n.expression.name + const declTypes = [ + 'VariableDeclaration', + 'ClassDeclaration', + 'TSDeclareFunction', + 'TSEnumDeclaration', + 'TSTypeAliasDeclaration', + 'TSInterfaceDeclaration', + 'TSAbstractClassDeclaration', + 'TSModuleDeclaration', + ] + const exportedDecls = ast.body.filter(({ type, id, declarations }) => + declTypes.includes(type) && + (id && id.name === exportedName || declarations.find(d => d.id.name === exportedName)) ) - moduleDecls.forEach((moduleDecl) => { - if (moduleDecl && moduleDecl.body && moduleDecl.body.body) { - moduleDecl.body.body.forEach((moduleBlockNode) => { + if (exportedDecls.length === 0) { + // Export is not referencing any local declaration, must be re-exporting + m.namespace.set('default', captureDoc(source, docStyleParsers, n)) + return + } + exportedDecls.forEach((decl) => { + if (decl.type === 'TSModuleDeclaration' && decl && decl.body && decl.body.body) { + decl.body.body.forEach((moduleBlockNode) => { // Export-assignment exports all members in the namespace, explicitly exported or not. - const exportedDecl = moduleBlockNode.type === 'ExportNamedDeclaration' ? + const namespaceDecl = moduleBlockNode.type === 'ExportNamedDeclaration' ? moduleBlockNode.declaration : moduleBlockNode - if (exportedDecl.type === 'VariableDeclaration') { - exportedDecl.declarations.forEach((decl) => - recursivePatternCapture(decl.id,(id) => m.namespace.set( + if (namespaceDecl.type === 'VariableDeclaration') { + namespaceDecl.declarations.forEach((d) => + recursivePatternCapture(d.id, (id) => m.namespace.set( id.name, - captureDoc(source, docStyleParsers, decl, exportedDecl, moduleBlockNode)) + captureDoc(source, docStyleParsers, decl, namespaceDecl, moduleBlockNode)) ) ) } else { m.namespace.set( - exportedDecl.id.name, + namespaceDecl.id.name, captureDoc(source, docStyleParsers, moduleBlockNode)) } }) + } else { + // Export as default + m.namespace.set('default', captureDoc(source, docStyleParsers, decl)) } }) } diff --git a/tests/files/typescript-default.ts b/tests/files/typescript-default.ts new file mode 100644 index 000000000..6d9a8f42c --- /dev/null +++ b/tests/files/typescript-default.ts @@ -0,0 +1 @@ +export default function foobar() {}; diff --git a/tests/files/typescript-export-assign-default-reexport.ts b/tests/files/typescript-export-assign-default-reexport.ts new file mode 100644 index 000000000..2fd502539 --- /dev/null +++ b/tests/files/typescript-export-assign-default-reexport.ts @@ -0,0 +1,2 @@ +import { getFoo } from './typescript'; +export = getFoo; diff --git a/tests/files/typescript-export-assign-default.d.ts b/tests/files/typescript-export-assign-default.d.ts new file mode 100644 index 000000000..f871ed926 --- /dev/null +++ b/tests/files/typescript-export-assign-default.d.ts @@ -0,0 +1,3 @@ +export = foobar; + +declare const foobar: number; diff --git a/tests/files/typescript-export-assign-mixed.d.ts b/tests/files/typescript-export-assign-mixed.d.ts new file mode 100644 index 000000000..8bf4c34b8 --- /dev/null +++ b/tests/files/typescript-export-assign-mixed.d.ts @@ -0,0 +1,11 @@ +export = foobar; + +declare function foobar(): void; +declare namespace foobar { + type MyType = string + enum MyEnum { + Foo, + Bar, + Baz + } +} diff --git a/tests/files/typescript-export-assign-merged.d.ts b/tests/files/typescript-export-assign-namespace-merged.d.ts similarity index 100% rename from tests/files/typescript-export-assign-merged.d.ts rename to tests/files/typescript-export-assign-namespace-merged.d.ts diff --git a/tests/files/typescript-export-assign.d.ts b/tests/files/typescript-export-assign-namespace.d.ts similarity index 100% rename from tests/files/typescript-export-assign.d.ts rename to tests/files/typescript-export-assign-namespace.d.ts diff --git a/tests/src/rules/default.js b/tests/src/rules/default.js index 4544285af..79d03e6c5 100644 --- a/tests/src/rules/default.js +++ b/tests/src/rules/default.js @@ -1,4 +1,4 @@ -import { test, SYNTAX_CASES } from '../utils' +import { test, SYNTAX_CASES, getTSParsers } from '../utils' import { RuleTester } from 'eslint' import { CASE_SENSITIVE_FS } from 'eslint-module-utils/resolve' @@ -152,3 +152,56 @@ if (!CASE_SENSITIVE_FS) { ], }) } + +context('TypeScript', function () { + getTSParsers().forEach((parser) => { + ruleTester.run(`default`, rule, { + valid: [ + test({ + code: `import foobar from "./typescript-default"`, + parser: parser, + settings: { + 'import/parsers': { [parser]: ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + }), + test({ + code: `import foobar from "./typescript-export-assign-default"`, + parser: parser, + settings: { + 'import/parsers': { [parser]: ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + }), + test({ + code: `import foobar from "./typescript-export-assign-mixed"`, + parser: parser, + settings: { + 'import/parsers': { [parser]: ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + }), + test({ + code: `import foobar from "./typescript-export-assign-default-reexport"`, + parser: parser, + settings: { + 'import/parsers': { [parser]: ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + }), + ], + + invalid: [ + test({ + code: `import foobar from "./typescript"`, + parser: parser, + settings: { + 'import/parsers': { [parser]: ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + errors: ['No default export found in imported module "./typescript".'], + }), + ], + }) + }) +}) diff --git a/tests/src/rules/named.js b/tests/src/rules/named.js index 303df1e14..eba7bec1a 100644 --- a/tests/src/rules/named.js +++ b/tests/src/rules/named.js @@ -285,7 +285,12 @@ ruleTester.run('named (export *)', rule, { context('TypeScript', function () { getTSParsers().forEach((parser) => { - ['typescript', 'typescript-declare', 'typescript-export-assign', 'typescript-export-assign-merged'].forEach((source) => { + [ + 'typescript', + 'typescript-declare', + 'typescript-export-assign-namespace', + 'typescript-export-assign-namespace-merged', + ].forEach((source) => { ruleTester.run(`named`, rule, { valid: [ test({