From e0592c906d745fe1fc580b34cda8ebdf1cb32e7a Mon Sep 17 00:00:00 2001 From: "Alex Taylor (alta)" Date: Wed, 1 Nov 2023 18:39:55 -0700 Subject: [PATCH] Preserve attached comments for printing ChainExpression nodes in Prettier V2 Summary: This fixes a bug we've identified while running codemods that causes some comments to get dropped when they are attached to `ChainExpression` nodes. This problem only exists in Prettier V2. Reviewed By: gkz Differential Revision: D50851144 fbshipit-source-id: 1acda37f80e301a6fe0ed52838df3de82ff2c8c1 --- .../src/utils/mutateESTreeASTForPrettier.js | 17 +++++++++-- .../__tests__/transform/transform-test.js | 30 +++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/tools/hermes-parser/js/hermes-parser/src/utils/mutateESTreeASTForPrettier.js b/tools/hermes-parser/js/hermes-parser/src/utils/mutateESTreeASTForPrettier.js index 6579ab93a28..4b2b171ab59 100644 --- a/tools/hermes-parser/js/hermes-parser/src/utils/mutateESTreeASTForPrettier.js +++ b/tools/hermes-parser/js/hermes-parser/src/utils/mutateESTreeASTForPrettier.js @@ -10,12 +10,22 @@ 'use strict'; -import type {ESNode, Program} from 'hermes-estree'; +import type {ESNode, Program, Comment} from 'hermes-estree'; import type {VisitorKeysType} from '../traverse/getVisitorKeys'; import {SimpleTransform} from '../transform/SimpleTransform'; // https://github.com/prettier/prettier/blob/d962466a828f8ef51435e3e8840178d90b7ec6cd/src/language-js/parse/postprocess/index.js#L161-L182 -function transformChainExpression(node: ESNode): ESNode { +function transformChainExpression( + node: ESNode, + comments: ?$ReadOnlyArray, +): ESNode { + if (comments != null) { + // $FlowExpectedError[prop-missing] + const joinedComments = comments.concat(node.comments ?? []); + // $FlowExpectedError[prop-missing] + // $FlowFixMe[cannot-write] + node.comments = joinedComments; + } switch (node.type) { case 'CallExpression': // $FlowExpectedError[cannot-spread-interface] @@ -59,7 +69,8 @@ export default function mutate( // so we have to apply their transform to our AST so it can actually format it. // Note: Only needed for prettier V2, this is supported in V3 if (node.type === 'ChainExpression') { - return transformChainExpression(node.expression); + // $FlowFixMe[prop-missing] + return transformChainExpression(node.expression, node?.comments); } // Prettier currently relies on comparing the `node` vs `node.value` start positions to know if an diff --git a/tools/hermes-parser/js/hermes-transform/__tests__/transform/transform-test.js b/tools/hermes-parser/js/hermes-transform/__tests__/transform/transform-test.js index a6d457d92f7..a899ba54c1a 100644 --- a/tools/hermes-parser/js/hermes-transform/__tests__/transform/transform-test.js +++ b/tools/hermes-parser/js/hermes-transform/__tests__/transform/transform-test.js @@ -1284,6 +1284,36 @@ foo?.[0]?.bar; `); }); + it('should preserve attached comments on ChainExpression nodes', async () => { + const code = `\ +foo( + // $FlowFixMe[prop-missing] + bar.baz, + // $FlowFixMe[prop-missing] + bar?.baz, +); +`; + const result = await transform(code, context => ({ + Identifier(node) { + context.replaceNode( + node, + t.Identifier({ + name: node.name, + }), + ); + return; + }, + })); + expect(result).toBe(`\ +foo( + // $FlowFixMe[prop-missing] + bar.baz, + // $FlowFixMe[prop-missing] + bar?.baz, +); +`); + }); + it('should correctly print method functions', async () => { const code = `\ type A = {};`;