diff --git a/packages/eslint-plugin/src/rules/promise-function-async.ts b/packages/eslint-plugin/src/rules/promise-function-async.ts index e2e65cfd1b6e..cf78f6c36ff3 100644 --- a/packages/eslint-plugin/src/rules/promise-function-async.ts +++ b/packages/eslint-plugin/src/rules/promise-function-async.ts @@ -92,10 +92,13 @@ export default util.createRule({ function validateNode(node: TSESTree.Node) { const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node); - const [callSignature] = checker + const signatures = checker .getTypeAtLocation(originalNode) .getCallSignatures(); - const returnType = checker.getReturnTypeOfSignature(callSignature); + if (!signatures.length) { + return; + } + const returnType = checker.getReturnTypeOfSignature(signatures[0]); if (!util.containsTypeByName(returnType, allAllowedPromiseNames)) { return; diff --git a/packages/eslint-plugin/tests/rules/promise-function-async.test.ts b/packages/eslint-plugin/tests/rules/promise-function-async.test.ts index 71f93d669bf3..fd1f5a90bfb1 100644 --- a/packages/eslint-plugin/tests/rules/promise-function-async.test.ts +++ b/packages/eslint-plugin/tests/rules/promise-function-async.test.ts @@ -45,7 +45,11 @@ class Test { return new Promise(); } } - ` + `, + // https://github.com/typescript-eslint/typescript-eslint/issues/227 + `export function valid(n: number) { return n; }`, + `export default function invalid(n: number) { return n; }`, + `class Foo { constructor() { } }` ], invalid: [ { diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 90fb8505ba00..5564456ca6e9 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -10,7 +10,6 @@ import { canContainDirective, createError, findNextToken, - fixExports, getBinaryExpressionType, getDeclarationKind, getLastModifier, @@ -111,29 +110,78 @@ export class Converter { this.allowPattern = allowPattern; } - let result: TSESTree.BaseNode | null = this.convertNode( - node as TSNode, - parent || node.parent - ); + let result = this.convertNode(node as TSNode, parent || node.parent); - if (result && this.options.shouldProvideParserServices) { - this.tsNodeToESTreeNodeMap.set(node, result); - if ( - node.kind !== SyntaxKind.ParenthesizedExpression && - node.kind !== SyntaxKind.ComputedPropertyName - ) { - // Parenthesized expressions and computed property names do not have individual nodes in ESTree. - // Therefore, result.type will never "match" node.kind if it is a ParenthesizedExpression - // or a ComputedPropertyName and, furthermore, will overwrite the "matching" node - this.esTreeNodeToTSNodeMap.set(result, node); - } - } + this.registerTSNodeInNodeMap(node, result); this.inTypeMode = typeMode; this.allowPattern = pattern; return result; } + /** + * Fixes the exports of the given ts.Node + * @param node the ts.Node + * @param result result + * @returns the ESTreeNode with fixed exports + */ + private fixExports( + node: ts.Node, + result: T + ): TSESTree.ExportDefaultDeclaration | TSESTree.ExportNamedDeclaration | T { + // check for exports + if (node.modifiers && node.modifiers[0].kind === SyntaxKind.ExportKeyword) { + /** + * Make sure that original node is registered instead of export + */ + this.registerTSNodeInNodeMap(node, result); + + const exportKeyword = node.modifiers[0]; + const nextModifier = node.modifiers[1]; + const declarationIsDefault = + nextModifier && nextModifier.kind === SyntaxKind.DefaultKeyword; + + const varToken = declarationIsDefault + ? findNextToken(nextModifier, this.ast, this.ast) + : findNextToken(exportKeyword, this.ast, this.ast); + + result.range[0] = varToken!.getStart(this.ast); + result.loc = getLocFor(result.range[0], result.range[1], this.ast); + + if (declarationIsDefault) { + return this.createNode(node, { + type: AST_NODE_TYPES.ExportDefaultDeclaration, + declaration: result, + range: [exportKeyword.getStart(this.ast), result.range[1]] + }); + } else { + return this.createNode(node, { + type: AST_NODE_TYPES.ExportNamedDeclaration, + declaration: result, + specifiers: [], + source: null, + range: [exportKeyword.getStart(this.ast), result.range[1]] + }); + } + } + + return result; + } + + /** + * Register specific TypeScript node into map with first ESTree node provided + */ + private registerTSNodeInNodeMap( + node: ts.Node, + result: TSESTree.BaseNode | null + ) { + if (result && this.options.shouldProvideParserServices) { + if (!this.tsNodeToESTreeNodeMap.has(node)) { + this.tsNodeToESTreeNodeMap.set(node, result); + } + } + } + /** * Converts a TypeScript node into an ESTree node. * @param child the child ts.Node @@ -176,6 +224,9 @@ export class Converter { result.loc = getLocFor(result.range[0], result.range[1], this.ast); } + if (result && this.options.shouldProvideParserServices) { + this.esTreeNodeToTSNodeMap.set(result, node); + } return result as T; } @@ -410,11 +461,7 @@ export class Converter { break; } - if (result && this.options.shouldProvideParserServices) { - this.tsNodeToESTreeNodeMap.set(node, result); - this.esTreeNodeToTSNodeMap.set(result, node); - } - + this.registerTSNodeInNodeMap(node, result); return result; } @@ -715,7 +762,7 @@ export class Converter { } // check for exports - return fixExports(node, result, this.ast); + return this.fixExports(node, result); } case SyntaxKind.VariableDeclaration: { @@ -764,7 +811,7 @@ export class Converter { } // check for exports - return fixExports(node, result, this.ast); + return this.fixExports(node, result); } // mostly for for-of, for-in @@ -1431,7 +1478,7 @@ export class Converter { } // check for exports - return fixExports(node, result, this.ast); + return this.fixExports(node, result); } // Modules @@ -2095,7 +2142,7 @@ export class Converter { } // check for exports - return fixExports(node, result, this.ast); + return this.fixExports(node, result); } case SyntaxKind.MethodSignature: { @@ -2310,7 +2357,7 @@ export class Converter { result.declare = true; } // check for exports - return fixExports(node, result, this.ast); + return this.fixExports(node, result); } case SyntaxKind.FirstTypeNode: { @@ -2356,7 +2403,7 @@ export class Converter { result.decorators = node.decorators.map(el => this.convertChild(el)); } // ...then check for exports - return fixExports(node, result, this.ast); + return this.fixExports(node, result); } case SyntaxKind.EnumMember: { @@ -2384,7 +2431,7 @@ export class Converter { result.global = true; } // ...then check for exports - return fixExports(node, result, this.ast); + return this.fixExports(node, result); } // TypeScript specific types diff --git a/packages/typescript-estree/src/node-utils.ts b/packages/typescript-estree/src/node-utils.ts index 9ff8a5c29c1a..bb03b99344a6 100644 --- a/packages/typescript-estree/src/node-utils.ts +++ b/packages/typescript-estree/src/node-utils.ts @@ -447,54 +447,6 @@ export function isOptional(node: { : false; } -/** - * Fixes the exports of the given ts.Node - * @param node the ts.Node - * @param result result - * @param ast the AST - * @returns the ESTreeNode with fixed exports - */ -export function fixExports( - node: ts.Node, - result: T, - ast: ts.SourceFile -): TSESTree.ExportDefaultDeclaration | TSESTree.ExportNamedDeclaration | T { - // check for exports - if (node.modifiers && node.modifiers[0].kind === SyntaxKind.ExportKeyword) { - const exportKeyword = node.modifiers[0]; - const nextModifier = node.modifiers[1]; - const declarationIsDefault = - nextModifier && nextModifier.kind === SyntaxKind.DefaultKeyword; - - const varToken = declarationIsDefault - ? findNextToken(nextModifier, ast, ast) - : findNextToken(exportKeyword, ast, ast); - - result.range![0] = varToken!.getStart(ast); - result.loc = getLocFor(result.range![0], result.range![1], ast); - - if (declarationIsDefault) { - return { - type: AST_NODE_TYPES.ExportDefaultDeclaration, - declaration: result as any, - range: [exportKeyword.getStart(ast), result.range![1]], - loc: getLocFor(exportKeyword.getStart(ast), result.range![1], ast) - }; - } else { - return { - type: AST_NODE_TYPES.ExportNamedDeclaration, - declaration: result as any, - range: [exportKeyword.getStart(ast), result.range![1]], - loc: getLocFor(exportKeyword.getStart(ast), result.range![1], ast), - specifiers: [], - source: null - }; - } - } - - return result; -} - /** * Returns the type of a given ts.Token * @param token the ts.Token diff --git a/packages/typescript-estree/src/ts-estree/ts-estree.ts b/packages/typescript-estree/src/ts-estree/ts-estree.ts index 57cc7c9016a8..4a9c7b91ae10 100644 --- a/packages/typescript-estree/src/ts-estree/ts-estree.ts +++ b/packages/typescript-estree/src/ts-estree/ts-estree.ts @@ -127,6 +127,7 @@ export type Node = | JSXOpeningFragment | JSXSpreadAttribute | JSXSpreadChild + | JSXMemberExpression | JSXText | LabeledStatement | Literal @@ -273,7 +274,7 @@ export type ExportDeclaration = | TSInterfaceDeclaration | TSModuleDeclaration | TSTypeAliasDeclaration - | VariableDeclarator; + | VariableDeclaration; export type Expression = | ArrowFunctionExpression | AssignmentExpression diff --git a/packages/typescript-estree/tests/lib/convert.ts b/packages/typescript-estree/tests/lib/convert.ts index 6fb1077a4714..ce9cf35fa0e8 100644 --- a/packages/typescript-estree/tests/lib/convert.ts +++ b/packages/typescript-estree/tests/lib/convert.ts @@ -149,4 +149,37 @@ describe('convert', () => { ); checkMaps(ast); }); + + it('nodeMaps should contain export node', () => { + const ast = convertCode(`export function foo () {}`); + + const instance = new Converter(ast, { + errorOnUnknownASTType: false, + useJSXTextNode: false, + shouldProvideParserServices: true + }); + const program = instance.convertProgram(); + const maps = instance.getASTMaps(); + + function checkMaps(child: any) { + child.forEachChild((node: any) => { + if (node.kind !== ts.SyntaxKind.EndOfFileToken) { + expect(ast).toBe( + maps.esTreeNodeToTSNodeMap.get(maps.tsNodeToESTreeNodeMap.get(ast)) + ); + } + checkMaps(node); + }); + } + + expect(ast).toBe( + maps.esTreeNodeToTSNodeMap.get(maps.tsNodeToESTreeNodeMap.get(ast)) + ); + + expect(maps.esTreeNodeToTSNodeMap.get(program.body[0])).toBeDefined(); + expect(program.body[0]).not.toBe( + maps.tsNodeToESTreeNodeMap.get(ast.statements[0]) + ); + checkMaps(ast); + }); }); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy