benjamn / recast

JavaScript syntax tree transformer, nondestructive pretty-printer, and automatic source map generator
MIT License
4.97k stars 346 forks source link

Line breaks being swallowed when fed to prettier #1240

Open Gregoor opened 1 year ago

Gregoor commented 1 year ago

Hey there,

I've run into a bug which only pops up when I pass a recast AST into babel. I don't see anything obviously wrong in the recast AST, so I am not entirely sure if this here is even the right place to post the issue, but I thought I'd at least try to see if someone has an intuitive idea.

import * as babelParser from '@babel/parser';
import prettier from 'prettier';
import recast from 'recast';

const code = ['// a', '', '// b', ''].join('\n');

const babelAST = babelParser.parse(code, {
  sourceType: 'module',
  plugins: ['jsx', 'typescript'],
  tokens: true,
  errorRecovery: true,
});

const recastAST = recast.parse(code, {
  parser: { parse: () => babelAST }
});

const formatted = prettier.format(code, { parser: () => recastAST });

const inn = code;
const out = formatted;
console.log(
  JSON.stringify({ inn, out, isSame: inn == out }, null, 2)
);

Runnable here on Replit

eventualbuddha commented 1 year ago

What are you trying to do? It may be the way you're integrating babel and recast isn't preserving line information.

Gregoor commented 1 year ago

I'm using recast to preserve as much of the source as possible when doing ast-based transformations. Tbh back when I integrated with it, I was not entirely sure if the way I am gluing these libraries correctly. That said, it did fix a source-preservation issue, so I was happy.

The example provided is pretty much exactly how I am using it in my real code.

eventualbuddha commented 1 year ago

In that case you might want to try @codemod/cli or jscodeshift or one of the other wrappers around recast that handles this layer for you.

Gregoor commented 1 year ago

Thanks for the pointer! It looks like recast.print is being used in both @codemod/core and jscodeshift, where I want to use Prettier. I'm wondering now if I could just print with recast first, and then feed that into prettier. I would lose performance to re-parsing though, so I think I'll still do some digging to narrow the issue down. In principle I don't think I'm doing something extensively off-menu: