From 01b2e8d36167b994fdaba3e58aa64b10a5c9658b Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Fri, 12 Jul 2019 21:10:54 +0800 Subject: [PATCH 1/4] [fix] `export`: false positive for typescript overloads --- src/rules/export.js | 16 ++++++++++++++++ tests/src/rules/export.js | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/rules/export.js b/src/rules/export.js index caa28e119f..c9e2cc8824 100644 --- a/src/rules/export.js +++ b/src/rules/export.js @@ -24,6 +24,19 @@ ambient namespaces: const rootProgram = 'root' const tsTypePrefix = 'type:' +/** + * Detect function overloads like: + * ```js + * export function foo(a: number) {} + * export function foo(a: string) {} + * ``` + * @param {Set} nodes + * @returns {boolean} + */ +function isTypescriptFunctionOverloads(nodes) { + return [...nodes].every(node => node.parent.type === 'FunctionDeclaration') +} + module.exports = { meta: { type: 'problem', @@ -34,6 +47,7 @@ module.exports = { create: function (context) { const namespace = new Map([[rootProgram, new Map()]]) + const isTypescriptFile = /\.ts|\.tsx$/.test(context.getFilename()) function addNamed(name, node, parent, isType) { if (!namespace.has(parent)) { @@ -123,6 +137,8 @@ module.exports = { for (let [name, nodes] of named) { if (nodes.size <= 1) continue + if (isTypescriptFile && isTypescriptFunctionOverloads(nodes)) continue + for (let node of nodes) { if (name === 'default') { context.report(node, 'Multiple default exports.') diff --git a/tests/src/rules/export.js b/tests/src/rules/export.js index 5ca7f458c3..f0341669e9 100644 --- a/tests/src/rules/export.js +++ b/tests/src/rules/export.js @@ -147,6 +147,22 @@ context('Typescript', function () { `, }, parserConfig)), + test(Object.assign({ + code: ` + export function fff(a: string) {}; + export function fff(a: number) {}; + `, + filename: 'foo.ts', + }, parserConfig)), + + test(Object.assign({ + code: ` + export function ggg(a: string) {}; + export function ggg(a: number) {}; + `, + filename: 'foo.tsx', + }, parserConfig)), + // namespace test(Object.assign({ code: ` From 8993f79152b13ba3784fb0e1a119ae24ae099b7d Mon Sep 17 00:00:00 2001 From: golopot Date: Sat, 13 Jul 2019 11:39:18 +0800 Subject: [PATCH 2/4] Change how function overloads are recognized --- src/rules/export.js | 18 +++++++++++------- tests/src/rules/export.js | 14 +++----------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/rules/export.js b/src/rules/export.js index c9e2cc8824..7739255c5b 100644 --- a/src/rules/export.js +++ b/src/rules/export.js @@ -26,15 +26,20 @@ const tsTypePrefix = 'type:' /** * Detect function overloads like: - * ```js - * export function foo(a: number) {} - * export function foo(a: string) {} + * ```ts + * export function foo(a: number); + * export function foo(a: string); + * export function foo(a: number|string) { return a; } * ``` - * @param {Set} nodes + * @param {Object[]} nodes * @returns {boolean} */ function isTypescriptFunctionOverloads(nodes) { - return [...nodes].every(node => node.parent.type === 'FunctionDeclaration') + return nodes.some(node => node.parent.type === 'TSDeclareFunction') && + nodes.every(node => ( + node.parent.type === 'TSDeclareFunction' || + node.parent.type === 'FunctionDeclaration' + )) } module.exports = { @@ -47,7 +52,6 @@ module.exports = { create: function (context) { const namespace = new Map([[rootProgram, new Map()]]) - const isTypescriptFile = /\.ts|\.tsx$/.test(context.getFilename()) function addNamed(name, node, parent, isType) { if (!namespace.has(parent)) { @@ -137,7 +141,7 @@ module.exports = { for (let [name, nodes] of named) { if (nodes.size <= 1) continue - if (isTypescriptFile && isTypescriptFunctionOverloads(nodes)) continue + if (isTypescriptFunctionOverloads([...nodes])) continue for (let node of nodes) { if (name === 'default') { diff --git a/tests/src/rules/export.js b/tests/src/rules/export.js index f0341669e9..70218ebb1c 100644 --- a/tests/src/rules/export.js +++ b/tests/src/rules/export.js @@ -149,18 +149,10 @@ context('Typescript', function () { test(Object.assign({ code: ` - export function fff(a: string) {}; - export function fff(a: number) {}; + export function fff(a: string); + export function fff(a: number); + export function fff(a: string|number) {}; `, - filename: 'foo.ts', - }, parserConfig)), - - test(Object.assign({ - code: ` - export function ggg(a: string) {}; - export function ggg(a: number) {}; - `, - filename: 'foo.tsx', }, parserConfig)), // namespace From 2443ba3477a9318cb9abcf3d687ed5c82ff9a6d5 Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Tue, 16 Jul 2019 20:41:46 +0800 Subject: [PATCH 3/4] refactor: use Array.from instead of spread --- src/rules/export.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rules/export.js b/src/rules/export.js index 7739255c5b..15ec5acf32 100644 --- a/src/rules/export.js +++ b/src/rules/export.js @@ -31,12 +31,12 @@ const tsTypePrefix = 'type:' * export function foo(a: string); * export function foo(a: number|string) { return a; } * ``` - * @param {Object[]} nodes + * @param {Set} nodes * @returns {boolean} */ function isTypescriptFunctionOverloads(nodes) { - return nodes.some(node => node.parent.type === 'TSDeclareFunction') && - nodes.every(node => ( + return Array.from(nodes).some(node => node.parent.type === 'TSDeclareFunction') && + Array.from(nodes).every(node => ( node.parent.type === 'TSDeclareFunction' || node.parent.type === 'FunctionDeclaration' )) @@ -141,7 +141,7 @@ module.exports = { for (let [name, nodes] of named) { if (nodes.size <= 1) continue - if (isTypescriptFunctionOverloads([...nodes])) continue + if (isTypescriptFunctionOverloads(nodes)) continue for (let node of nodes) { if (name === 'default') { From e48eb0e01169e75c457a75f914f3e10dea1d1867 Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Wed, 17 Jul 2019 19:24:47 +0800 Subject: [PATCH 4/4] refactor: avoid Array.from the same thing twice --- src/rules/export.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/rules/export.js b/src/rules/export.js index 15ec5acf32..a9fba849e0 100644 --- a/src/rules/export.js +++ b/src/rules/export.js @@ -35,11 +35,8 @@ const tsTypePrefix = 'type:' * @returns {boolean} */ function isTypescriptFunctionOverloads(nodes) { - return Array.from(nodes).some(node => node.parent.type === 'TSDeclareFunction') && - Array.from(nodes).every(node => ( - node.parent.type === 'TSDeclareFunction' || - node.parent.type === 'FunctionDeclaration' - )) + const types = new Set(Array.from(nodes, node => node.parent.type)) + return types.size === 2 && types.has('TSDeclareFunction') && types.has('FunctionDeclaration') } module.exports = {