From 6ccc462409f7cea4df7fcbe8cf9ef92cfbd5a7c9 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Thu, 13 Jan 2022 09:54:06 +0900 Subject: [PATCH] Print comments for parenthesized TS keyword types (#12070) * Prefer node.start for TS keyword types * Add tests * Add changelog * Refactor * Use isTsKeywordType * Fix lint problems --- changelog_unreleased/javascript/12070.md | 17 +++ src/language-js/parse/postprocess/index.js | 10 +- src/language-js/print/typescript.js | 3 +- src/language-js/utils.js | 5 + .../__snapshots__/jsfmt.spec.js.snap | 125 ++++++++++++++++++ .../keyword-types/conditional-types.ts | 14 ++ .../typescript/keyword-types/jsfmt.spec.js | 1 + .../keyword-types-with-parens-comments.ts | 52 ++++++++ 8 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 changelog_unreleased/javascript/12070.md create mode 100644 tests/format/typescript/keyword-types/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/format/typescript/keyword-types/conditional-types.ts create mode 100644 tests/format/typescript/keyword-types/jsfmt.spec.js create mode 100644 tests/format/typescript/keyword-types/keyword-types-with-parens-comments.ts diff --git a/changelog_unreleased/javascript/12070.md b/changelog_unreleased/javascript/12070.md new file mode 100644 index 000000000..66bf7183e --- /dev/null +++ b/changelog_unreleased/javascript/12070.md @@ -0,0 +1,17 @@ +#### Print comments for parenthesized TS keyword types with `babel-ts` parser (#12070 by @sosukesuzuki) + + +```ts +// Input +let foo: ( + // comment + never +); + +// Prettier stable +Error: Comment "comment" was not printed. Please report this error! + +// Prettier main +let foo: // comment +never; +``` diff --git a/src/language-js/parse/postprocess/index.js b/src/language-js/parse/postprocess/index.js index bf01da5eb..97c543a38 100644 --- a/src/language-js/parse/postprocess/index.js +++ b/src/language-js/parse/postprocess/index.js @@ -3,6 +3,7 @@ const { getLast } = require("../../../common/util.js"); const { locStart, locEnd } = require("../../loc.js"); const { isTypeCastComment } = require("../../comments.js"); +const { isTsKeywordType } = require("../../utils.js"); const visitNode = require("./visitNode.js"); const { throwErrorForInvalidNodes } = require("./typescript.js"); @@ -79,7 +80,14 @@ function postprocess(ast, options) { } // remove redundant TypeScript nodes case "TSParenthesizedType": { - node.typeAnnotation.range = [locStart(node), locEnd(node)]; + if ( + !( + isTsKeywordType(node.typeAnnotation) || + node.typeAnnotation.type === "TSThisType" + ) + ) { + node.typeAnnotation.range = [locStart(node), locEnd(node)]; + } return node.typeAnnotation; } case "TSTypeParameter": diff --git a/src/language-js/print/typescript.js b/src/language-js/print/typescript.js index 9d5547775..693ffcd8a 100644 --- a/src/language-js/print/typescript.js +++ b/src/language-js/print/typescript.js @@ -20,6 +20,7 @@ const { shouldPrintComma, isCallExpression, isMemberExpression, + isTsKeywordType, } = require("../utils.js"); const { locStart, locEnd } = require("../loc.js"); @@ -58,7 +59,7 @@ function printTypescript(path, options, print) { return; } - if (node.type.endsWith("Keyword")) { + if (isTsKeywordType(node)) { return node.type.slice(2, -7).toLowerCase(); } diff --git a/src/language-js/utils.js b/src/language-js/utils.js index 693e52b80..ccb5f4add 100644 --- a/src/language-js/utils.js +++ b/src/language-js/utils.js @@ -1322,6 +1322,10 @@ const markerForIfWithoutBlockAndSameLineComment = Symbol( "ifWithoutBlockAndSameLineComment" ); +function isTsKeywordType({ type }) { + return type.startsWith("TS") && type.endsWith("Keyword"); +} + module.exports = { getFunctionParameters, iterateFunctionParametersPath, @@ -1387,4 +1391,5 @@ module.exports = { getComments, CommentCheckFlags, markerForIfWithoutBlockAndSameLineComment, + isTsKeywordType, }; diff --git a/tests/format/typescript/keyword-types/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/keyword-types/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000..8f2097f3b --- /dev/null +++ b/tests/format/typescript/keyword-types/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,125 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`conditional-types.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +export type UnwrappedResultRow = { + [P in keyof T]: ( + T[P] extends Req ? ( + a + ) : ( + T[P] extends Opt ? ( + b + ) : ( + // TEST + never + ) + ) + ); +}; + +=====================================output===================================== +export type UnwrappedResultRow = { + [P in keyof T]: T[P] extends Req + ? a + : T[P] extends Opt + ? b + : // TEST + never; +}; + +================================================================================ +`; + +exports[`keyword-types-with-parens-comments.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +let foo: ( + // comment + any +); +let foo: ( + // comment + null +); +let foo: ( + // comment + this +); +let foo: ( + // comment + number +); +let foo: ( + // comment + void +); +let foo: ( + // comment + boolean +); +let foo: ( + // comment + bigint +); +let foo: ( + // comment + symbol +); +let foo: ( + // comment + string +); +let foo: ( + // comment + never +); +let foo: ( + // comment + object +); +let foo: ( + // comment + undefined +); +let foo: ( + // comment + unknown +); + +=====================================output===================================== +let foo: // comment +any; +let foo: // comment +null; +let foo: // comment +this; +let foo: // comment +number; +let foo: // comment +void; +let foo: // comment +boolean; +let foo: // comment +bigint; +let foo: // comment +symbol; +let foo: // comment +string; +let foo: // comment +never; +let foo: // comment +object; +let foo: // comment +undefined; +let foo: // comment +unknown; + +================================================================================ +`; diff --git a/tests/format/typescript/keyword-types/conditional-types.ts b/tests/format/typescript/keyword-types/conditional-types.ts new file mode 100644 index 000000000..96aef0495 --- /dev/null +++ b/tests/format/typescript/keyword-types/conditional-types.ts @@ -0,0 +1,14 @@ +export type UnwrappedResultRow = { + [P in keyof T]: ( + T[P] extends Req ? ( + a + ) : ( + T[P] extends Opt ? ( + b + ) : ( + // TEST + never + ) + ) + ); +}; diff --git a/tests/format/typescript/keyword-types/jsfmt.spec.js b/tests/format/typescript/keyword-types/jsfmt.spec.js new file mode 100644 index 000000000..2ea3bb6eb --- /dev/null +++ b/tests/format/typescript/keyword-types/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname, ["typescript"]); diff --git a/tests/format/typescript/keyword-types/keyword-types-with-parens-comments.ts b/tests/format/typescript/keyword-types/keyword-types-with-parens-comments.ts new file mode 100644 index 000000000..9587c0dbb --- /dev/null +++ b/tests/format/typescript/keyword-types/keyword-types-with-parens-comments.ts @@ -0,0 +1,52 @@ +let foo: ( + // comment + any +); +let foo: ( + // comment + null +); +let foo: ( + // comment + this +); +let foo: ( + // comment + number +); +let foo: ( + // comment + void +); +let foo: ( + // comment + boolean +); +let foo: ( + // comment + bigint +); +let foo: ( + // comment + symbol +); +let foo: ( + // comment + string +); +let foo: ( + // comment + never +); +let foo: ( + // comment + object +); +let foo: ( + // comment + undefined +); +let foo: ( + // comment + unknown +);