diff --git a/lib/ast-converter.js b/lib/ast-converter.js index eb492da..f40359d 100644 --- a/lib/ast-converter.js +++ b/lib/ast-converter.js @@ -452,6 +452,42 @@ module.exports = function(ast, extra) { }; } + /** + * Converts a TSNode's typeArguments array to a flow-like typeParameters node + * @param {Array} typeArguments TSNode typeArguments + * @returns {TypeParameterInstantiation} TypeParameterInstantiation node + */ + function convertTypeArgumentsToTypeParameters(typeArguments) { + var firstTypeArgument = typeArguments[0]; + var lastTypeArgument = typeArguments[typeArguments.length - 1]; + return { + type: "TypeParameterInstantiation", + range: [ + firstTypeArgument.pos - 1, + lastTypeArgument.end + 1 + ], + loc: getLocFor(firstTypeArgument.pos - 1, lastTypeArgument.end + 1, ast), + params: typeArguments.map(function(typeArgument) { + /** + * Have to manually calculate the start of the range, + * because TypeScript includes leading whitespace but Flow does not + */ + var typeArgumentStart = (typeArgument.typeName && typeArgument.typeName.text) + ? typeArgument.end - typeArgument.typeName.text.length + : typeArgument.pos; + return { + type: "GenericTypeAnnotation", + range: [ + typeArgumentStart, + typeArgument.end + ], + loc: getLocFor(typeArgumentStart, typeArgument.end, ast), + id: convertChild(typeArgument.typeName) + }; + }) + }; + } + /** * Converts a child into a class implements node. This creates an intermediary * ClassImplements node to match what Flow does. @@ -460,12 +496,16 @@ module.exports = function(ast, extra) { */ function convertClassImplements(child) { var id = convertChild(child.expression); - return { + var classImplementsNode = { type: "ClassImplements", loc: id.loc, range: id.range, id: id }; + if (child.typeArguments && child.typeArguments.length) { + classImplementsNode.typeParameters = convertTypeArgumentsToTypeParameters(child.typeArguments); + } + return classImplementsNode; } /** diff --git a/tests/fixtures/typescript/basics/class-with-implements-generic-multiple.result.js b/tests/fixtures/typescript/basics/class-with-implements-generic-multiple.result.js new file mode 100644 index 0000000..6dce4c6 --- /dev/null +++ b/tests/fixtures/typescript/basics/class-with-implements-generic-multiple.result.js @@ -0,0 +1,400 @@ +module.exports = { + "type": "Program", + "range": [ + 0, + 35 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ClassDeclaration", + "range": [ + 0, + 35 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "range": [ + 6, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "name": "Foo" + }, + "body": { + "type": "ClassBody", + "body": [], + "range": [ + 31, + 35 + ], + "loc": { + "start": { + "line": 1, + "column": 31 + }, + "end": { + "line": 3, + "column": 1 + } + } + }, + "superClass": null, + "implements": [ + { + "type": "ClassImplements", + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 24 + } + }, + "range": [ + 21, + 24 + ], + "id": { + "type": "Identifier", + "range": [ + 21, + 24 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 24 + } + }, + "name": "Bar" + }, + "typeParameters": { + "type": "TypeParameterInstantiation", + "range": [ + 24, + 30 + ], + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 30 + } + }, + "params": [ + { + "type": "GenericTypeAnnotation", + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 26 + } + }, + "id": { + "type": "Identifier", + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 26 + } + }, + "name": "S" + } + }, + { + "type": "GenericTypeAnnotation", + "range": [ + 28, + 29 + ], + "loc": { + "start": { + "line": 1, + "column": 28 + }, + "end": { + "line": 1, + "column": 29 + } + }, + "id": { + "type": "Identifier", + "range": [ + 28, + 29 + ], + "loc": { + "start": { + "line": 1, + "column": 28 + }, + "end": { + "line": 1, + "column": 29 + } + }, + "name": "T" + } + } + ] + } + } + ] + } + ], + "sourceType": "script", + "tokens": [ + { + "type": "Keyword", + "value": "class", + "range": [ + 0, + 5 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 5 + } + } + }, + { + "type": "Identifier", + "value": "Foo", + "range": [ + 6, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 9 + } + } + }, + { + "type": "Keyword", + "value": "implements", + "range": [ + 10, + 20 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 20 + } + } + }, + { + "type": "Identifier", + "value": "Bar", + "range": [ + 21, + 24 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 24 + } + } + }, + { + "type": "Punctuator", + "value": "<", + "range": [ + 24, + 25 + ], + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 25 + } + } + }, + { + "type": "Identifier", + "value": "S", + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 26 + } + } + }, + { + "type": "Punctuator", + "value": ",", + "range": [ + 26, + 27 + ], + "loc": { + "start": { + "line": 1, + "column": 26 + }, + "end": { + "line": 1, + "column": 27 + } + } + }, + { + "type": "Identifier", + "value": "T", + "range": [ + 28, + 29 + ], + "loc": { + "start": { + "line": 1, + "column": 28 + }, + "end": { + "line": 1, + "column": 29 + } + } + }, + { + "type": "Punctuator", + "value": ">", + "range": [ + 29, + 30 + ], + "loc": { + "start": { + "line": 1, + "column": 29 + }, + "end": { + "line": 1, + "column": 30 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 31, + 32 + ], + "loc": { + "start": { + "line": 1, + "column": 31 + }, + "end": { + "line": 1, + "column": 32 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 34, + 35 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + } + } + ] +}; diff --git a/tests/fixtures/typescript/basics/class-with-implements-generic-multiple.src.ts b/tests/fixtures/typescript/basics/class-with-implements-generic-multiple.src.ts new file mode 100644 index 0000000..0a02bc2 --- /dev/null +++ b/tests/fixtures/typescript/basics/class-with-implements-generic-multiple.src.ts @@ -0,0 +1,3 @@ +class Foo implements Bar { + +} diff --git a/tests/fixtures/typescript/basics/class-with-implements-generic.result.js b/tests/fixtures/typescript/basics/class-with-implements-generic.result.js new file mode 100644 index 0000000..f28bc5d --- /dev/null +++ b/tests/fixtures/typescript/basics/class-with-implements-generic.result.js @@ -0,0 +1,329 @@ +module.exports = { + "type": "Program", + "range": [ + 0, + 32 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ClassDeclaration", + "range": [ + 0, + 32 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "range": [ + 6, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "name": "Foo" + }, + "body": { + "type": "ClassBody", + "body": [], + "range": [ + 28, + 32 + ], + "loc": { + "start": { + "line": 1, + "column": 28 + }, + "end": { + "line": 3, + "column": 1 + } + } + }, + "superClass": null, + "implements": [ + { + "type": "ClassImplements", + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 24 + } + }, + "range": [ + 21, + 24 + ], + "id": { + "type": "Identifier", + "range": [ + 21, + 24 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 24 + } + }, + "name": "Bar" + }, + "typeParameters": { + "type": "TypeParameterInstantiation", + "range": [ + 24, + 27 + ], + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 27 + } + }, + "params": [ + { + "type": "GenericTypeAnnotation", + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 26 + } + }, + "id": { + "type": "Identifier", + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 26 + } + }, + "name": "S" + }, + } + ] + } + } + ] + } + ], + "sourceType": "script", + "tokens": [ + { + "type": "Keyword", + "value": "class", + "range": [ + 0, + 5 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 5 + } + } + }, + { + "type": "Identifier", + "value": "Foo", + "range": [ + 6, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 9 + } + } + }, + { + "type": "Keyword", + "value": "implements", + "range": [ + 10, + 20 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 20 + } + } + }, + { + "type": "Identifier", + "value": "Bar", + "range": [ + 21, + 24 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 24 + } + } + }, + { + "type": "Punctuator", + "value": "<", + "range": [ + 24, + 25 + ], + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 25 + } + } + }, + { + "type": "Identifier", + "value": "S", + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 26 + } + } + }, + { + "type": "Punctuator", + "value": ">", + "range": [ + 26, + 27 + ], + "loc": { + "start": { + "line": 1, + "column": 26 + }, + "end": { + "line": 1, + "column": 27 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 28, + 29 + ], + "loc": { + "start": { + "line": 1, + "column": 28 + }, + "end": { + "line": 1, + "column": 29 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 31, + 32 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + } + } + ] +}; \ No newline at end of file diff --git a/tests/fixtures/typescript/basics/class-with-implements-generic.src.ts b/tests/fixtures/typescript/basics/class-with-implements-generic.src.ts new file mode 100644 index 0000000..b18efb9 --- /dev/null +++ b/tests/fixtures/typescript/basics/class-with-implements-generic.src.ts @@ -0,0 +1,3 @@ +class Foo implements Bar { + +}