From 406914077706dee7bae34e19851c0962cb1635ef Mon Sep 17 00:00:00 2001 From: Reyad Attiyat Date: Sun, 19 Feb 2017 17:20:57 -0600 Subject: [PATCH] Fix: Label empty body functions (fixes #92) There are rules in eslint that expect FunctionExpression nodes to contain a body. We should not produce an invalid estree node if we use the estree node types. --- lib/ast-converter.js | 26 +- ...tract-class-with-abstract-method.result.js | 2 +- .../basics/declare-function.result.js | 4 +- ...unction-with-multiple-signatures.result.js | 1212 +++++++++++++++++ .../function-with-multiple-signatures.src.ts | 6 + 5 files changed, 1244 insertions(+), 6 deletions(-) create mode 100644 tests/fixtures/typescript/basics/function-with-multiple-signatures.result.js create mode 100644 tests/fixtures/typescript/basics/function-with-multiple-signatures.src.ts diff --git a/lib/ast-converter.js b/lib/ast-converter.js index b978b90..eb9b7a6 100644 --- a/lib/ast-converter.js +++ b/lib/ast-converter.js @@ -879,6 +879,10 @@ module.exports = function(ast, extra) { } } + if (!node.body) { + functionDeclarationType = "TSEmptyBodyFunctionDeclaration"; + } + /** * Prefix FunctionDeclarations within TypeScript namespaces with "TS" */ @@ -1074,6 +1078,7 @@ module.exports = function(ast, extra) { // TODO: double-check that these positions are correct var methodLoc = ast.getLineAndCharacterOfPosition(node.name.end + 1), nodeIsMethod = (node.kind === SyntaxKind.MethodDeclaration), + isEmptyBody = !(node.body), method = { type: "FunctionExpression", id: null, @@ -1127,9 +1132,10 @@ module.exports = function(ast, extra) { /** * TypeScript class methods can be defined as "abstract" */ - var methodDefinitionType = "MethodDefinition"; + var methodDefinitionType = "MethodDefinition", + isAbstractMethod = false; if (node.modifiers && node.modifiers.length) { - var isAbstractMethod = node.modifiers.some(function(modifier) { + isAbstractMethod = node.modifiers.some(function(modifier) { return modifier.kind === ts.SyntaxKind.AbstractKeyword; }); if (isAbstractMethod) { @@ -1137,6 +1143,13 @@ module.exports = function(ast, extra) { } } + if (isEmptyBody) { + if (!isAbstractMethod) { + methodDefinitionType = "TSEmptyBodyMethodDefinition"; + } + method.type = "TSEmptyBodyFunctionExpression"; + } + assign(result, { type: methodDefinitionType, key: convertChild(node.name), @@ -1167,6 +1180,7 @@ module.exports = function(ast, extra) { var constructorIsStatic = Boolean(node.flags & ts.NodeFlags.Static), firstConstructorToken = constructorIsStatic ? ts.findNextToken(node.getFirstToken(), ast) : node.getFirstToken(), constructorLoc = ast.getLineAndCharacterOfPosition(node.parameters.pos - 1), + constructorIsEmptyBody = !(node.body), constructor = { type: "FunctionExpression", id: null, @@ -1230,8 +1244,14 @@ module.exports = function(ast, extra) { }; } + var constructorMethodDefinitionType = "MethodDefinition"; + if (constructorIsEmptyBody) { + constructorMethodDefinitionType = "TSEmptyBodyMethodDefinition"; + constructor.type = "TSEmptyBodyFunctionExpression"; + } + assign(result, { - type: "MethodDefinition", + type: constructorMethodDefinitionType, key: constructorKey, value: constructor, computed: constructorIsComputed, diff --git a/tests/fixtures/typescript/basics/abstract-class-with-abstract-method.result.js b/tests/fixtures/typescript/basics/abstract-class-with-abstract-method.result.js index c476c03..c607109 100644 --- a/tests/fixtures/typescript/basics/abstract-class-with-abstract-method.result.js +++ b/tests/fixtures/typescript/basics/abstract-class-with-abstract-method.result.js @@ -89,7 +89,7 @@ module.exports = { "name": "createSocket" }, "value": { - "type": "FunctionExpression", + "type": "TSEmptyBodyFunctionExpression", "id": null, "generator": false, "expression": false, diff --git a/tests/fixtures/typescript/basics/declare-function.result.js b/tests/fixtures/typescript/basics/declare-function.result.js index efe5741..deb80cd 100644 --- a/tests/fixtures/typescript/basics/declare-function.result.js +++ b/tests/fixtures/typescript/basics/declare-function.result.js @@ -16,7 +16,7 @@ module.exports = { }, "body": [ { - "type": "DeclareFunction", + "type": "TSEmptyBodyFunctionDeclaration", "range": [ 0, 42 @@ -344,4 +344,4 @@ module.exports = { } } ] -}; \ No newline at end of file +}; diff --git a/tests/fixtures/typescript/basics/function-with-multiple-signatures.result.js b/tests/fixtures/typescript/basics/function-with-multiple-signatures.result.js new file mode 100644 index 0000000..25dd563 --- /dev/null +++ b/tests/fixtures/typescript/basics/function-with-multiple-signatures.result.js @@ -0,0 +1,1212 @@ +module.exports = { + "type": "Program", + "range": [ + 1, + 141 + ], + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "body": [ + { + "type": "TSEmptyBodyFunctionDeclaration", + "range": [ + 1, + 35 + ], + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 34 + } + }, + "id": { + "type": "Identifier", + "range": [ + 10, + 13 + ], + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 12 + } + }, + "name": "foo" + }, + "generator": false, + "expression": false, + "async": false, + "params": [ + { + "type": "Identifier", + "range": [ + 14, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 13 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "name": "bar", + "typeAnnotation": { + "type": "TypeAnnotation", + "loc": { + "start": { + "line": 2, + "column": 18 + }, + "end": { + "line": 2, + "column": 24 + } + }, + "range": [ + 19, + 25 + ], + "typeAnnotation": { + "type": "TSStringKeyword", + "range": [ + 19, + 25 + ], + "loc": { + "start": { + "line": 2, + "column": 18 + }, + "end": { + "line": 2, + "column": 24 + } + } + } + } + } + ], + "body": null, + "returnType": { + "type": "TypeAnnotation", + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 33 + } + }, + "range": [ + 28, + 34 + ], + "typeAnnotation": { + "type": "TSStringKeyword", + "range": [ + 28, + 34 + ], + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 33 + } + } + } + } + }, + { + "type": "TSEmptyBodyFunctionDeclaration", + "range": [ + 36, + 70 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 34 + } + }, + "id": { + "type": "Identifier", + "range": [ + 45, + 48 + ], + "loc": { + "start": { + "line": 3, + "column": 9 + }, + "end": { + "line": 3, + "column": 12 + } + }, + "name": "foo" + }, + "generator": false, + "expression": false, + "async": false, + "params": [ + { + "type": "Identifier", + "range": [ + 49, + 52 + ], + "loc": { + "start": { + "line": 3, + "column": 13 + }, + "end": { + "line": 3, + "column": 16 + } + }, + "name": "bar", + "typeAnnotation": { + "type": "TypeAnnotation", + "loc": { + "start": { + "line": 3, + "column": 18 + }, + "end": { + "line": 3, + "column": 24 + } + }, + "range": [ + 54, + 60 + ], + "typeAnnotation": { + "type": "TSNumberKeyword", + "range": [ + 54, + 60 + ], + "loc": { + "start": { + "line": 3, + "column": 18 + }, + "end": { + "line": 3, + "column": 24 + } + } + } + } + } + ], + "body": null, + "returnType": { + "type": "TypeAnnotation", + "loc": { + "start": { + "line": 3, + "column": 27 + }, + "end": { + "line": 3, + "column": 33 + } + }, + "range": [ + 63, + 69 + ], + "typeAnnotation": { + "type": "TSNumberKeyword", + "range": [ + 63, + 69 + ], + "loc": { + "start": { + "line": 3, + "column": 27 + }, + "end": { + "line": 3, + "column": 33 + } + } + } + } + }, + { + "type": "FunctionDeclaration", + "range": [ + 71, + 141 + ], + "loc": { + "start": { + "line": 4, + "column": 0 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "range": [ + 80, + 83 + ], + "loc": { + "start": { + "line": 4, + "column": 9 + }, + "end": { + "line": 4, + "column": 12 + } + }, + "name": "foo" + }, + "generator": false, + "expression": false, + "async": false, + "params": [ + { + "type": "Identifier", + "range": [ + 84, + 87 + ], + "loc": { + "start": { + "line": 4, + "column": 13 + }, + "end": { + "line": 4, + "column": 16 + } + }, + "name": "bar", + "typeAnnotation": { + "type": "TypeAnnotation", + "loc": { + "start": { + "line": 4, + "column": 18 + }, + "end": { + "line": 4, + "column": 32 + } + }, + "range": [ + 89, + 103 + ], + "typeAnnotation": { + "type": "TSUnionType", + "range": [ + 89, + 103 + ], + "loc": { + "start": { + "line": 4, + "column": 18 + }, + "end": { + "line": 4, + "column": 32 + } + }, + "types": [ + { + "type": "TSStringKeyword", + "range": [ + 89, + 95 + ], + "loc": { + "start": { + "line": 4, + "column": 18 + }, + "end": { + "line": 4, + "column": 24 + } + } + }, + { + "type": "TSNumberKeyword", + "range": [ + 97, + 103 + ], + "loc": { + "start": { + "line": 4, + "column": 26 + }, + "end": { + "line": 4, + "column": 32 + } + } + } + ] + } + } + } + ], + "body": { + "type": "BlockStatement", + "range": [ + 122, + 141 + ], + "loc": { + "start": { + "line": 4, + "column": 51 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "body": [ + { + "type": "ReturnStatement", + "range": [ + 128, + 139 + ], + "loc": { + "start": { + "line": 5, + "column": 4 + }, + "end": { + "line": 5, + "column": 15 + } + }, + "argument": { + "type": "Identifier", + "range": [ + 135, + 138 + ], + "loc": { + "start": { + "line": 5, + "column": 11 + }, + "end": { + "line": 5, + "column": 14 + } + }, + "name": "bar" + } + } + ] + }, + "returnType": { + "type": "TypeAnnotation", + "loc": { + "start": { + "line": 4, + "column": 35 + }, + "end": { + "line": 4, + "column": 50 + } + }, + "range": [ + 106, + 121 + ], + "typeAnnotation": { + "type": "TSUnionType", + "range": [ + 106, + 121 + ], + "loc": { + "start": { + "line": 4, + "column": 35 + }, + "end": { + "line": 4, + "column": 50 + } + }, + "types": [ + { + "type": "TSStringKeyword", + "range": [ + 106, + 112 + ], + "loc": { + "start": { + "line": 4, + "column": 35 + }, + "end": { + "line": 4, + "column": 41 + } + } + }, + { + "type": "TSNumberKeyword", + "range": [ + 115, + 121 + ], + "loc": { + "start": { + "line": 4, + "column": 44 + }, + "end": { + "line": 4, + "column": 50 + } + } + } + ] + } + } + } + ], + "sourceType": "script", + "tokens": [ + { + "type": "Keyword", + "value": "function", + "range": [ + 1, + 9 + ], + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 8 + } + } + }, + { + "type": "Identifier", + "value": "foo", + "range": [ + 10, + 13 + ], + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 12 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 13, + 14 + ], + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 13 + } + } + }, + { + "type": "Identifier", + "value": "bar", + "range": [ + 14, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 13 + }, + "end": { + "line": 2, + "column": 16 + } + } + }, + { + "type": "Punctuator", + "value": ":", + "range": [ + 17, + 18 + ], + "loc": { + "start": { + "line": 2, + "column": 16 + }, + "end": { + "line": 2, + "column": 17 + } + } + }, + { + "type": "Identifier", + "value": "string", + "range": [ + 19, + 25 + ], + "loc": { + "start": { + "line": 2, + "column": 18 + }, + "end": { + "line": 2, + "column": 24 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "line": 2, + "column": 24 + }, + "end": { + "line": 2, + "column": 25 + } + } + }, + { + "type": "Punctuator", + "value": ":", + "range": [ + 26, + 27 + ], + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 26 + } + } + }, + { + "type": "Identifier", + "value": "string", + "range": [ + 28, + 34 + ], + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 33 + } + } + }, + { + "type": "Punctuator", + "value": ";", + "range": [ + 34, + 35 + ], + "loc": { + "start": { + "line": 2, + "column": 33 + }, + "end": { + "line": 2, + "column": 34 + } + } + }, + { + "type": "Keyword", + "value": "function", + "range": [ + 36, + 44 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 8 + } + } + }, + { + "type": "Identifier", + "value": "foo", + "range": [ + 45, + 48 + ], + "loc": { + "start": { + "line": 3, + "column": 9 + }, + "end": { + "line": 3, + "column": 12 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 48, + 49 + ], + "loc": { + "start": { + "line": 3, + "column": 12 + }, + "end": { + "line": 3, + "column": 13 + } + } + }, + { + "type": "Identifier", + "value": "bar", + "range": [ + 49, + 52 + ], + "loc": { + "start": { + "line": 3, + "column": 13 + }, + "end": { + "line": 3, + "column": 16 + } + } + }, + { + "type": "Punctuator", + "value": ":", + "range": [ + 52, + 53 + ], + "loc": { + "start": { + "line": 3, + "column": 16 + }, + "end": { + "line": 3, + "column": 17 + } + } + }, + { + "type": "Identifier", + "value": "number", + "range": [ + 54, + 60 + ], + "loc": { + "start": { + "line": 3, + "column": 18 + }, + "end": { + "line": 3, + "column": 24 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 60, + 61 + ], + "loc": { + "start": { + "line": 3, + "column": 24 + }, + "end": { + "line": 3, + "column": 25 + } + } + }, + { + "type": "Punctuator", + "value": ":", + "range": [ + 61, + 62 + ], + "loc": { + "start": { + "line": 3, + "column": 25 + }, + "end": { + "line": 3, + "column": 26 + } + } + }, + { + "type": "Identifier", + "value": "number", + "range": [ + 63, + 69 + ], + "loc": { + "start": { + "line": 3, + "column": 27 + }, + "end": { + "line": 3, + "column": 33 + } + } + }, + { + "type": "Punctuator", + "value": ";", + "range": [ + 69, + 70 + ], + "loc": { + "start": { + "line": 3, + "column": 33 + }, + "end": { + "line": 3, + "column": 34 + } + } + }, + { + "type": "Keyword", + "value": "function", + "range": [ + 71, + 79 + ], + "loc": { + "start": { + "line": 4, + "column": 0 + }, + "end": { + "line": 4, + "column": 8 + } + } + }, + { + "type": "Identifier", + "value": "foo", + "range": [ + 80, + 83 + ], + "loc": { + "start": { + "line": 4, + "column": 9 + }, + "end": { + "line": 4, + "column": 12 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 83, + 84 + ], + "loc": { + "start": { + "line": 4, + "column": 12 + }, + "end": { + "line": 4, + "column": 13 + } + } + }, + { + "type": "Identifier", + "value": "bar", + "range": [ + 84, + 87 + ], + "loc": { + "start": { + "line": 4, + "column": 13 + }, + "end": { + "line": 4, + "column": 16 + } + } + }, + { + "type": "Punctuator", + "value": ":", + "range": [ + 87, + 88 + ], + "loc": { + "start": { + "line": 4, + "column": 16 + }, + "end": { + "line": 4, + "column": 17 + } + } + }, + { + "type": "Identifier", + "value": "string", + "range": [ + 89, + 95 + ], + "loc": { + "start": { + "line": 4, + "column": 18 + }, + "end": { + "line": 4, + "column": 24 + } + } + }, + { + "type": "Punctuator", + "value": "|", + "range": [ + 95, + 96 + ], + "loc": { + "start": { + "line": 4, + "column": 24 + }, + "end": { + "line": 4, + "column": 25 + } + } + }, + { + "type": "Identifier", + "value": "number", + "range": [ + 97, + 103 + ], + "loc": { + "start": { + "line": 4, + "column": 26 + }, + "end": { + "line": 4, + "column": 32 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 103, + 104 + ], + "loc": { + "start": { + "line": 4, + "column": 32 + }, + "end": { + "line": 4, + "column": 33 + } + } + }, + { + "type": "Punctuator", + "value": ":", + "range": [ + 104, + 105 + ], + "loc": { + "start": { + "line": 4, + "column": 33 + }, + "end": { + "line": 4, + "column": 34 + } + } + }, + { + "type": "Identifier", + "value": "string", + "range": [ + 106, + 112 + ], + "loc": { + "start": { + "line": 4, + "column": 35 + }, + "end": { + "line": 4, + "column": 41 + } + } + }, + { + "type": "Punctuator", + "value": "|", + "range": [ + 113, + 114 + ], + "loc": { + "start": { + "line": 4, + "column": 42 + }, + "end": { + "line": 4, + "column": 43 + } + } + }, + { + "type": "Identifier", + "value": "number", + "range": [ + 115, + 121 + ], + "loc": { + "start": { + "line": 4, + "column": 44 + }, + "end": { + "line": 4, + "column": 50 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 122, + 123 + ], + "loc": { + "start": { + "line": 4, + "column": 51 + }, + "end": { + "line": 4, + "column": 52 + } + } + }, + { + "type": "Keyword", + "value": "return", + "range": [ + 128, + 134 + ], + "loc": { + "start": { + "line": 5, + "column": 4 + }, + "end": { + "line": 5, + "column": 10 + } + } + }, + { + "type": "Identifier", + "value": "bar", + "range": [ + 135, + 138 + ], + "loc": { + "start": { + "line": 5, + "column": 11 + }, + "end": { + "line": 5, + "column": 14 + } + } + }, + { + "type": "Punctuator", + "value": ";", + "range": [ + 138, + 139 + ], + "loc": { + "start": { + "line": 5, + "column": 14 + }, + "end": { + "line": 5, + "column": 15 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 140, + 141 + ], + "loc": { + "start": { + "line": 6, + "column": 0 + }, + "end": { + "line": 6, + "column": 1 + } + } + } + ] +}; diff --git a/tests/fixtures/typescript/basics/function-with-multiple-signatures.src.ts b/tests/fixtures/typescript/basics/function-with-multiple-signatures.src.ts new file mode 100644 index 0000000..c80bbc7 --- /dev/null +++ b/tests/fixtures/typescript/basics/function-with-multiple-signatures.src.ts @@ -0,0 +1,6 @@ + +function foo(bar: string): string; +function foo(bar: number): number; +function foo(bar: string| number): string | number { + return bar; +}