diff --git a/lib/ast-converter.js b/lib/ast-converter.js index b63aa32..88b0ae8 100644 --- a/lib/ast-converter.js +++ b/lib/ast-converter.js @@ -1027,13 +1027,26 @@ module.exports = function(ast, extra) { return convertedParam; }); - var methodNameIsComputed = (node.name.kind === SyntaxKind.ComputedPropertyName); + var isMethodNameComputed = (node.name.kind === SyntaxKind.ComputedPropertyName); + + /** + * TypeScript class methods can be defined as "abstract" + */ + var methodDefinitionType = "MethodDefinition"; + if (node.modifiers && node.modifiers.length) { + var isAbstractMethod = node.modifiers.some(function(modifier) { + return modifier.kind === ts.SyntaxKind.AbstractKeyword; + }); + if (isAbstractMethod) { + methodDefinitionType = "TSAbstractMethodDefinition"; + } + } assign(result, { - type: "MethodDefinition", + type: methodDefinitionType, key: convertChild(node.name), value: method, - computed: methodNameIsComputed, + computed: isMethodNameComputed, static: Boolean(node.flags & ts.NodeFlags.Static), kind: "method", decorators: (node.decorators) ? node.decorators.map(function(d) { @@ -1330,15 +1343,32 @@ module.exports = function(ast, extra) { case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: + var heritageClauses = node.heritageClauses || []; var lastClassToken = heritageClauses.length ? heritageClauses[heritageClauses.length - 1] : node.name; - /** - * We need check for modifiers, and use the last one, as there - * could be multiple before the open brace - */ + var classNodeType = SyntaxKind[node.kind]; + if (node.modifiers && node.modifiers.length) { + + /** + * TypeScript class declarations can be defined as "abstract" + */ + if (node.kind === SyntaxKind.ClassDeclaration) { + var isAbstractClass = node.modifiers.some(function(modifier) { + return modifier.kind === ts.SyntaxKind.AbstractKeyword; + }); + if (isAbstractClass) { + classNodeType = "TSAbstract" + classNodeType; + } + } + + /** + * We need check for modifiers, and use the last one, as there + * could be multiple before the open brace + */ var lastModifier = node.modifiers[node.modifiers.length - 1]; lastClassToken = ts.findNextToken(lastModifier, ast); + } else if (!lastClassToken) { // no name lastClassToken = node.getFirstToken(); } @@ -1355,7 +1385,7 @@ module.exports = function(ast, extra) { hasImplements = heritageClauses.length > 0; assign(result, { - type: SyntaxKind[node.kind], + type: classNodeType, id: convertChild(node.name), body: { type: "ClassBody", 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 new file mode 100644 index 0000000..607b55a --- /dev/null +++ b/tests/fixtures/typescript/basics/abstract-class-with-abstract-method.result.js @@ -0,0 +1,520 @@ +module.exports = { + "type": "Program", + "range": [ + 0, + 86 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ExportNamedDeclaration", + "declaration": { + "type": "TSAbstractClassDeclaration", + "range": [ + 16, + 86 + ], + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "range": [ + 22, + 36 + ], + "loc": { + "start": { + "line": 1, + "column": 22 + }, + "end": { + "line": 1, + "column": 36 + } + }, + "name": "AbstractSocket" + }, + "body": { + "type": "ClassBody", + "body": [ + { + "type": "TSAbstractMethodDefinition", + "range": [ + 43, + 84 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 45 + } + }, + "key": { + "type": "Identifier", + "range": [ + 52, + 64 + ], + "loc": { + "start": { + "line": 2, + "column": 13 + }, + "end": { + "line": 2, + "column": 25 + } + }, + "name": "createSocket" + }, + "value": { + "type": "FunctionExpression", + "id": null, + "params": [], + "generator": false, + "expression": false, + "body": null, + "range": [ + 64, + 84 + ], + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 45 + } + }, + "returnType": { + "type": "TypeAnnotation", + "loc": { + "start": { + "line": 2, + "column": 29 + }, + "end": { + "line": 2, + "column": 44 + } + }, + "range": [ + 68, + 83 + ], + "typeAnnotation": { + "type": "TSTypeReference", + "range": [ + 68, + 83 + ], + "loc": { + "start": { + "line": 2, + "column": 29 + }, + "end": { + "line": 2, + "column": 44 + } + }, + "flags": 0, + "typeName": { + "type": "Identifier", + "range": [ + 68, + 75 + ], + "loc": { + "start": { + "line": 2, + "column": 29 + }, + "end": { + "line": 2, + "column": 36 + } + }, + "name": "Promise" + }, + "typeArguments": [ + { + "type": "TSStringKeyword", + "range": [ + 76, + 82 + ], + "loc": { + "start": { + "line": 2, + "column": 37 + }, + "end": { + "line": 2, + "column": 43 + } + }, + "flags": 0 + } + ] + } + } + }, + "computed": false, + "static": false, + "kind": "method", + "decorators": [] + } + ], + "range": [ + 22, + 86 + ], + "loc": { + "start": { + "line": 1, + "column": 22 + }, + "end": { + "line": 3, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "decorators": [] + }, + "range": [ + 0, + 86 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "specifiers": [], + "source": null + } + ], + "sourceType": "module", + "tokens": [ + { + "type": "Keyword", + "value": "export", + "range": [ + 0, + 6 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + } + }, + { + "type": "Identifier", + "value": "abstract", + "range": [ + 7, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 15 + } + } + }, + { + "type": "Keyword", + "value": "class", + "range": [ + 16, + 21 + ], + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 21 + } + } + }, + { + "type": "Identifier", + "value": "AbstractSocket", + "range": [ + 22, + 36 + ], + "loc": { + "start": { + "line": 1, + "column": 22 + }, + "end": { + "line": 1, + "column": 36 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 37, + 38 + ], + "loc": { + "start": { + "line": 1, + "column": 37 + }, + "end": { + "line": 1, + "column": 38 + } + } + }, + { + "type": "Identifier", + "value": "abstract", + "range": [ + 43, + 51 + ], + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 12 + } + } + }, + { + "type": "Identifier", + "value": "createSocket", + "range": [ + 52, + 64 + ], + "loc": { + "start": { + "line": 2, + "column": 13 + }, + "end": { + "line": 2, + "column": 25 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 64, + 65 + ], + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 26 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 65, + 66 + ], + "loc": { + "start": { + "line": 2, + "column": 26 + }, + "end": { + "line": 2, + "column": 27 + } + } + }, + { + "type": "Punctuator", + "value": ":", + "range": [ + 66, + 67 + ], + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 28 + } + } + }, + { + "type": "Identifier", + "value": "Promise", + "range": [ + 68, + 75 + ], + "loc": { + "start": { + "line": 2, + "column": 29 + }, + "end": { + "line": 2, + "column": 36 + } + } + }, + { + "type": "Punctuator", + "value": "<", + "range": [ + 75, + 76 + ], + "loc": { + "start": { + "line": 2, + "column": 36 + }, + "end": { + "line": 2, + "column": 37 + } + } + }, + { + "type": "Identifier", + "value": "string", + "range": [ + 76, + 82 + ], + "loc": { + "start": { + "line": 2, + "column": 37 + }, + "end": { + "line": 2, + "column": 43 + } + } + }, + { + "type": "Punctuator", + "value": ">", + "range": [ + 82, + 83 + ], + "loc": { + "start": { + "line": 2, + "column": 43 + }, + "end": { + "line": 2, + "column": 44 + } + } + }, + { + "type": "Punctuator", + "value": ";", + "range": [ + 83, + 84 + ], + "loc": { + "start": { + "line": 2, + "column": 44 + }, + "end": { + "line": 2, + "column": 45 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 85, + 86 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + } + } + ] +}; diff --git a/tests/fixtures/typescript/basics/abstract-class-with-abstract-method.src.ts b/tests/fixtures/typescript/basics/abstract-class-with-abstract-method.src.ts new file mode 100644 index 0000000..537036b --- /dev/null +++ b/tests/fixtures/typescript/basics/abstract-class-with-abstract-method.src.ts @@ -0,0 +1,3 @@ +export abstract class AbstractSocket { + abstract createSocket(): Promise; +} \ No newline at end of file