From 57fff67d7912b71caa6a64abb14c5a26f8e8d219 Mon Sep 17 00:00:00 2001 From: Kai Cataldo Date: Sun, 24 Dec 2017 00:38:56 -0500 Subject: [PATCH 1/2] Fix: Remove all tokens inside comments from tokens array (fixes #422) --- lib/node-utils.js | 28 ++++++++++++++++++- .../external-fixtures/jsdoc-indent.js | 11 +++++++- tests/integration/typescript.spec.js | 2 +- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/lib/node-utils.js b/lib/node-utils.js index 928ff14..3ed6e4d 100644 --- a/lib/node-utils.js +++ b/lib/node-utils.js @@ -244,6 +244,32 @@ function isComma(token) { return token.kind === SyntaxKind.CommaToken; } +/** + * Returns true if the given TSToken is a comment + * @param {TSToken} token the TypeScript token + * @returns {boolean} is commment + */ +function isComment(token) { + return (token.kind === SyntaxKind.SingleLineCommentTrivia || token.kind === SyntaxKind.MultiLineCommentTrivia) || (token.kind >= SyntaxKind.JSDocTypeExpression && token.kind <= SyntaxKind.JSDocTypeLiteral); +} + +/** + * Returns true if the given TSToken is inside a comment + * Non-comment type tokens are generated for types in JSDoc Blocks + * @param {TSToken} token the TypeScript token + * @returns {boolean} is inside a commment + */ +function isInsideComment(token) { + if (token.kind === SyntaxKind.SourceFile) { + return false; + } + if (isComment(token)) { + return true; + } + return isInsideComment(token.parent); +} + + /** * Returns the binary expression type of the given TSToken * @param {TSToken} operator the operator token @@ -693,7 +719,7 @@ function convertTokens(ast) { * @returns {undefined} */ function walk(node) { - if (isToken(node) && node.kind !== SyntaxKind.EndOfFileToken) { + if (isToken(node) && !isInsideComment(node) && node.kind !== SyntaxKind.EndOfFileToken) { const converted = convertToken(node, ast); if (converted) { diff --git a/tests/integration/external-fixtures/jsdoc-indent.js b/tests/integration/external-fixtures/jsdoc-indent.js index 25641d5..0854f1b 100644 --- a/tests/integration/external-fixtures/jsdoc-indent.js +++ b/tests/integration/external-fixtures/jsdoc-indent.js @@ -9,4 +9,13 @@ foo; /** * a */ -foo; \ No newline at end of file +foo; + +/** + * This is a function. + * @param {String} bar + * @returns {String} returns bar + */ +function foo(bar) { + return bar; +} diff --git a/tests/integration/typescript.spec.js b/tests/integration/typescript.spec.js index 6a83a13..c2a6f80 100644 --- a/tests/integration/typescript.spec.js +++ b/tests/integration/typescript.spec.js @@ -80,7 +80,7 @@ describe("TypeScript", () => { ); }); - it("should not produce any lint errors on valid JSDoc indentation (#344)", () => { + it("should not produce any lint errors on valid JSDoc indentation (#344 & #422)", () => { verifyAndAssertMessages( loadExternalFixture("jsdoc-indent"), { From 26a0d26a1e6c458c8ce69ca110316e93f9f788ea Mon Sep 17 00:00:00 2001 From: Kai Cataldo Date: Sun, 24 Dec 2017 14:04:41 -0500 Subject: [PATCH 2/2] Refactor to avoid crawling up tree on every converted token --- lib/node-utils.js | 41 +-- tests/fixtures/comments/jsdoc-comment.src.js | 8 + .../external-fixtures/jsdoc-indent.js | 2 +- tests/lib/__snapshots__/comments.js.snap | 341 ++++++++++++++++++ 4 files changed, 370 insertions(+), 22 deletions(-) create mode 100644 tests/fixtures/comments/jsdoc-comment.src.js diff --git a/lib/node-utils.js b/lib/node-utils.js index 3ed6e4d..2501507 100644 --- a/lib/node-utils.js +++ b/lib/node-utils.js @@ -185,7 +185,9 @@ module.exports = { convertTokens, getNodeContainer, isWithinTypeAnnotation, - isTypeKeyword + isTypeKeyword, + isComment, + isJSDocComment }; /* eslint-enable no-use-before-define */ @@ -245,31 +247,23 @@ function isComma(token) { } /** - * Returns true if the given TSToken is a comment - * @param {TSToken} token the TypeScript token - * @returns {boolean} is commment + * Returns true if the given TSNode is a comment + * @param {TSNode} node the TypeScript node + * @returns {boolean} is commment */ -function isComment(token) { - return (token.kind === SyntaxKind.SingleLineCommentTrivia || token.kind === SyntaxKind.MultiLineCommentTrivia) || (token.kind >= SyntaxKind.JSDocTypeExpression && token.kind <= SyntaxKind.JSDocTypeLiteral); +function isComment(node) { + return node.kind === SyntaxKind.SingleLineCommentTrivia || node.kind === SyntaxKind.MultiLineCommentTrivia; } /** - * Returns true if the given TSToken is inside a comment - * Non-comment type tokens are generated for types in JSDoc Blocks - * @param {TSToken} token the TypeScript token - * @returns {boolean} is inside a commment + * Returns true if the given TSNode is a JSDoc comment + * @param {TSNode} node the TypeScript node + * @returns {boolean} is JSDoc comment */ -function isInsideComment(token) { - if (token.kind === SyntaxKind.SourceFile) { - return false; - } - if (isComment(token)) { - return true; - } - return isInsideComment(token.parent); +function isJSDocComment(node) { + return node.kind === SyntaxKind.JSDocComment; } - /** * Returns the binary expression type of the given TSToken * @param {TSToken} operator the operator token @@ -282,7 +276,6 @@ function getBinaryExpressionType(operator) { return "LogicalExpression"; } return "BinaryExpression"; - } /** @@ -719,7 +712,13 @@ function convertTokens(ast) { * @returns {undefined} */ function walk(node) { - if (isToken(node) && !isInsideComment(node) && node.kind !== SyntaxKind.EndOfFileToken) { + // TypeScript generates tokens for types in JSDoc blocks. Comment tokens + // and their children should not be walked or added to the resulting tokens list. + if (isComment(node) || isJSDocComment(node)) { + return; + } + + if (isToken(node) && node.kind !== SyntaxKind.EndOfFileToken) { const converted = convertToken(node, ast); if (converted) { diff --git a/tests/fixtures/comments/jsdoc-comment.src.js b/tests/fixtures/comments/jsdoc-comment.src.js new file mode 100644 index 0000000..29298a1 --- /dev/null +++ b/tests/fixtures/comments/jsdoc-comment.src.js @@ -0,0 +1,8 @@ +/** + * This is a function. + * @param {String} bar some string + * @returns {String} returns bar + */ +function foo(bar) { + return bar; +} diff --git a/tests/integration/external-fixtures/jsdoc-indent.js b/tests/integration/external-fixtures/jsdoc-indent.js index 0854f1b..c402637 100644 --- a/tests/integration/external-fixtures/jsdoc-indent.js +++ b/tests/integration/external-fixtures/jsdoc-indent.js @@ -13,7 +13,7 @@ foo; /** * This is a function. - * @param {String} bar + * @param {String} bar some string * @returns {String} returns bar */ function foo(bar) { diff --git a/tests/lib/__snapshots__/comments.js.snap b/tests/lib/__snapshots__/comments.js.snap index 72ee0ac..41309c3 100644 --- a/tests/lib/__snapshots__/comments.js.snap +++ b/tests/lib/__snapshots__/comments.js.snap @@ -830,6 +830,347 @@ Object { } `; +exports[`Comments fixtures/jsdoc-comment.src 1`] = ` +Object { + "body": Array [ + Object { + "async": false, + "body": Object { + "body": Array [ + Object { + "argument": Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 7, + }, + "start": Object { + "column": 11, + "line": 7, + }, + }, + "name": "bar", + "range": Array [ + 130, + 133, + ], + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 15, + "line": 7, + }, + "start": Object { + "column": 4, + "line": 7, + }, + }, + "range": Array [ + 123, + 134, + ], + "type": "ReturnStatement", + }, + ], + "loc": Object { + "end": Object { + "column": 1, + "line": 8, + }, + "start": Object { + "column": 18, + "line": 6, + }, + }, + "range": Array [ + 117, + 136, + ], + "type": "BlockStatement", + }, + "expression": false, + "generator": false, + "id": Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 6, + }, + "start": Object { + "column": 9, + "line": 6, + }, + }, + "name": "foo", + "range": Array [ + 108, + 111, + ], + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 1, + "line": 8, + }, + "start": Object { + "column": 0, + "line": 6, + }, + }, + "params": Array [ + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 6, + }, + "start": Object { + "column": 13, + "line": 6, + }, + }, + "name": "bar", + "range": Array [ + 112, + 115, + ], + "type": "Identifier", + }, + ], + "range": Array [ + 99, + 136, + ], + "type": "FunctionDeclaration", + }, + ], + "comments": Array [ + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 5, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 98, + ], + "type": "Block", + "value": "* + * This is a function. + * @param {String} bar some string + * @returns {String} returns bar + ", + }, + ], + "loc": Object { + "end": Object { + "column": 0, + "line": 9, + }, + "start": Object { + "column": 0, + "line": 6, + }, + }, + "range": Array [ + 99, + 137, + ], + "sourceType": "script", + "tokens": Array [ + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 6, + }, + "start": Object { + "column": 0, + "line": 6, + }, + }, + "range": Array [ + 99, + 107, + ], + "type": "Keyword", + "value": "function", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 6, + }, + "start": Object { + "column": 9, + "line": 6, + }, + }, + "range": Array [ + 108, + 111, + ], + "type": "Identifier", + "value": "foo", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 6, + }, + "start": Object { + "column": 12, + "line": 6, + }, + }, + "range": Array [ + 111, + 112, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 6, + }, + "start": Object { + "column": 13, + "line": 6, + }, + }, + "range": Array [ + 112, + 115, + ], + "type": "Identifier", + "value": "bar", + }, + Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 6, + }, + "start": Object { + "column": 16, + "line": 6, + }, + }, + "range": Array [ + 115, + 116, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 6, + }, + "start": Object { + "column": 18, + "line": 6, + }, + }, + "range": Array [ + 117, + 118, + ], + "type": "Punctuator", + "value": "{", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 7, + }, + "start": Object { + "column": 4, + "line": 7, + }, + }, + "range": Array [ + 123, + 129, + ], + "type": "Keyword", + "value": "return", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 7, + }, + "start": Object { + "column": 11, + "line": 7, + }, + }, + "range": Array [ + 130, + 133, + ], + "type": "Identifier", + "value": "bar", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 7, + }, + "start": Object { + "column": 14, + "line": 7, + }, + }, + "range": Array [ + 133, + 134, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 8, + }, + "start": Object { + "column": 0, + "line": 8, + }, + }, + "range": Array [ + 135, + 136, + ], + "type": "Punctuator", + "value": "}", + }, + ], + "type": "Program", +} +`; + exports[`Comments fixtures/jsx-block-comment.src 1`] = ` Object { "body": Array [