From 7933c81934bd4421d4cbb3967fa2165edaeb2742 Mon Sep 17 00:00:00 2001 From: Reyad Attiyat Date: Wed, 1 Feb 2017 16:21:07 -0600 Subject: [PATCH] Fix: Calculate range correctly when class is exported (fixes #152) The range of a class body should be from the opening brace to the closing brace. To find the opening brace the ast converter parses over modifiers of the class declaration and assumes it is the last token after the last node modifier. This assumption is not always true when the class is exported. This commit ensures we only skip over modifiers which are after the class name or heritage clause. --- lib/ast-converter.js | 4 +- .../modules/export-default-class.result.js | 168 +++++++++++++++ .../modules/export-default-class.src.js | 3 + .../export-default-named-class.result.js | 203 ++++++++++++++++++ .../modules/export-default-named-class.src.js | 3 + .../modules/export-named-class.result.js | 188 ++++++++++++++++ .../modules/export-named-class.src.js | 3 + ...tract-class-with-abstract-method.result.js | 6 +- 8 files changed, 574 insertions(+), 4 deletions(-) create mode 100644 tests/fixtures/ecma-features/modules/export-default-class.result.js create mode 100644 tests/fixtures/ecma-features/modules/export-default-class.src.js create mode 100644 tests/fixtures/ecma-features/modules/export-default-named-class.result.js create mode 100644 tests/fixtures/ecma-features/modules/export-default-named-class.src.js create mode 100644 tests/fixtures/ecma-features/modules/export-named-class.result.js create mode 100644 tests/fixtures/ecma-features/modules/export-named-class.src.js diff --git a/lib/ast-converter.js b/lib/ast-converter.js index 865023e..4078ed3 100644 --- a/lib/ast-converter.js +++ b/lib/ast-converter.js @@ -1476,7 +1476,9 @@ module.exports = function(ast, extra) { * could be multiple before the open brace */ var lastModifier = node.modifiers[node.modifiers.length - 1]; - lastClassToken = ts.findNextToken(lastModifier, ast); + if (!lastClassToken || lastModifier.pos > lastClassToken.pos) { + lastClassToken = ts.findNextToken(lastModifier, ast); + } } else if (!lastClassToken) { // no name lastClassToken = node.getFirstToken(); diff --git a/tests/fixtures/ecma-features/modules/export-default-class.result.js b/tests/fixtures/ecma-features/modules/export-default-class.result.js new file mode 100644 index 0000000..68d9008 --- /dev/null +++ b/tests/fixtures/ecma-features/modules/export-default-class.result.js @@ -0,0 +1,168 @@ +module.exports = { + "type": "Program", + "range": [ + 0, + 25 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ExportDefaultDeclaration", + "declaration": { + "type": "ClassDeclaration", + "range": [ + 15, + 25 + ], + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": null, + "body": { + "type": "ClassBody", + "body": [], + "range": [ + 21, + 25 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 3, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "decorators": [] + }, + "range": [ + 0, + 25 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + } + } + ], + "sourceType": "module", + "tokens": [ + { + "type": "Keyword", + "value": "export", + "range": [ + 0, + 6 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + } + }, + { + "type": "Keyword", + "value": "default", + "range": [ + 7, + 14 + ], + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 14 + } + } + }, + { + "type": "Keyword", + "value": "class", + "range": [ + 15, + 20 + ], + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 1, + "column": 20 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 21, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 22 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 24, + 25 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + } + } + ] +}; diff --git a/tests/fixtures/ecma-features/modules/export-default-class.src.js b/tests/fixtures/ecma-features/modules/export-default-class.src.js new file mode 100644 index 0000000..3509c96 --- /dev/null +++ b/tests/fixtures/ecma-features/modules/export-default-class.src.js @@ -0,0 +1,3 @@ +export default class { + +} diff --git a/tests/fixtures/ecma-features/modules/export-default-named-class.result.js b/tests/fixtures/ecma-features/modules/export-default-named-class.result.js new file mode 100644 index 0000000..fa48618 --- /dev/null +++ b/tests/fixtures/ecma-features/modules/export-default-named-class.result.js @@ -0,0 +1,203 @@ +module.exports = { + "type": "Program", + "range": [ + 0, + 30 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ExportDefaultDeclaration", + "declaration": { + "type": "ClassDeclaration", + "range": [ + 15, + 30 + ], + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "range": [ + 21, + 25 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 25 + } + }, + "name": "Test" + }, + "body": { + "type": "ClassBody", + "body": [], + "range": [ + 26, + 30 + ], + "loc": { + "start": { + "line": 1, + "column": 26 + }, + "end": { + "line": 3, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "decorators": [] + }, + "range": [ + 0, + 30 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + } + } + ], + "sourceType": "module", + "tokens": [ + { + "type": "Keyword", + "value": "export", + "range": [ + 0, + 6 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + } + }, + { + "type": "Keyword", + "value": "default", + "range": [ + 7, + 14 + ], + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 14 + } + } + }, + { + "type": "Keyword", + "value": "class", + "range": [ + 15, + 20 + ], + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 1, + "column": 20 + } + } + }, + { + "type": "Identifier", + "value": "Test", + "range": [ + 21, + 25 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 25 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 26, + 27 + ], + "loc": { + "start": { + "line": 1, + "column": 26 + }, + "end": { + "line": 1, + "column": 27 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 29, + 30 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + } + } + ] +}; diff --git a/tests/fixtures/ecma-features/modules/export-default-named-class.src.js b/tests/fixtures/ecma-features/modules/export-default-named-class.src.js new file mode 100644 index 0000000..b2ded7d --- /dev/null +++ b/tests/fixtures/ecma-features/modules/export-default-named-class.src.js @@ -0,0 +1,3 @@ +export default class Test { + +} diff --git a/tests/fixtures/ecma-features/modules/export-named-class.result.js b/tests/fixtures/ecma-features/modules/export-named-class.result.js new file mode 100644 index 0000000..b265290 --- /dev/null +++ b/tests/fixtures/ecma-features/modules/export-named-class.result.js @@ -0,0 +1,188 @@ +module.exports = { + "type": "Program", + "range": [ + 0, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ExportNamedDeclaration", + "declaration": { + "type": "ClassDeclaration", + "range": [ + 7, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "range": [ + 13, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 13 + }, + "end": { + "line": 1, + "column": 17 + } + }, + "name": "Test" + }, + "body": { + "type": "ClassBody", + "body": [], + "range": [ + 18, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 18 + }, + "end": { + "line": 3, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "decorators": [] + }, + "range": [ + 0, + 22 + ], + "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": "Keyword", + "value": "class", + "range": [ + 7, + 12 + ], + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 12 + } + } + }, + { + "type": "Identifier", + "value": "Test", + "range": [ + 13, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 13 + }, + "end": { + "line": 1, + "column": 17 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 18, + 19 + ], + "loc": { + "start": { + "line": 1, + "column": 18 + }, + "end": { + "line": 1, + "column": 19 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 21, + 22 + ], + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + } + } + ] +}; + diff --git a/tests/fixtures/ecma-features/modules/export-named-class.src.js b/tests/fixtures/ecma-features/modules/export-named-class.src.js new file mode 100644 index 0000000..3cb35e9 --- /dev/null +++ b/tests/fixtures/ecma-features/modules/export-named-class.src.js @@ -0,0 +1,3 @@ +export class Test { + +} 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 5d253fe..c476c03 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 @@ -190,13 +190,13 @@ module.exports = { } ], "range": [ - 22, + 37, 86 ], "loc": { "start": { "line": 1, - "column": 22 + "column": 37 }, "end": { "line": 3, @@ -517,4 +517,4 @@ module.exports = { } } ] -}; \ No newline at end of file +};