benjamn / recast

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

How to print all `Properties` in a `ObjectPattern` in the same line? #240

Open kumarharsh opened 8 years ago

kumarharsh commented 8 years ago

Hi, I'm trying to modify my code, and converting a variableDeclarator into an arrowFunctionExpression like this:

http://astexplorer.net/#/JxZcRETnjv

As you can see, each Property in the ObjectPattern passed as params to the arrow function is put in a new line, even though I'm specifying the template string for them to be in the same line:

  return statement`
      generateStyles = ({theme, palette, geometry}) => ${body}
  `;

gives:

generateStyles = (
  {
    theme,
    palette,
    geometry,
  },
) => ({
  ...body...
});

I looked at the options available in recast, but couldn't find one which forces params to be in one line. Is there a way to do this?

nene commented 8 years ago

I also ran into this. I was trying to programmatically generate an ObjectPattern, but the formatting that Recast produced was far from desirable.

Found a workaround by instead building the desired output string, parsing it with recast, and extracting the ObjectPattern node from there. Something like this:

function createObjectPattern(propNames) {
  const js = `function foo({${propNames.join(', ')}}) {};`;
  return recast.parse(js).program.body[0].params[0];
}
danielo515 commented 3 years ago

I also ran into this. I was trying to programmatically generate an ObjectPattern, but the formatting that Recast produced was far from desirable.

Found a workaround by instead building the desired output string, parsing it with recast, and extracting the ObjectPattern node from there. Something like this:

function createObjectPattern(propNames) {
  const js = `function foo({${propNames.join(', ')}}) {};`;
  return recast.parse(js).program.body[0].params[0];
}

Wow, this works like a charm, not sure why. Seems that recast is respecting the styles of what it parsed. For example, if you add spaces around your braces { x } instead of {x} that change is reflected on the output.

I was using this code on my codemods:

export default function (file, api) {
  const j = api.jscodeshift;
  const shortProperty = (j, identifier) => {
    return { ...j.objectProperty(identifier, identifier), shorthand: true };
  };
  const call = j.variableDeclaration("const", [
      j.variableDeclarator(
        j.objectPattern([shortProperty(j,j.identifier("__"))]),
        j.callExpression(j.identifier("usePulyglot"), [
          j.identifier("phrases")
        ])
      )
    ])

    return j(call).toSource();
}

And I was getting the same weird behaviours as this. @nene solution not only works like a charm and it's shorter, it is also easier to understand 😄

danielo515 commented 3 years ago

This is getting stupidly complex. In my new scenario I have to remove one property from one argument object destructuring. I can not just find the right property and remove it because recast introduces extra newlines that I don't know how to avoid. Therefore, I have to use this workaround to, instead, generate a totally new object argument and put that one in place. Now I have to preserve type annotations. My first guess was: ok, create the new object argument and just copy the type annotations over, right? Well, NO, because if I just copy the type annotations the problem of the newlines appear again. So now, I have to deal with a more complex template, guess the proper type parser (flow or TS? ) and inject the type praising for it to be a simple type annotation with just a name. Very brittle and error prone.

I really wish to see this fixed.

danielo515 commented 3 years ago

I will have to accept the fact that I have to fix the ugly formatting later and fix my tests to support this ugly extra line endings nonsense. I have found many more cases where the nice provided workaround will just not work:

And I'm pretty sure there are others where, deleting one property and leaving the rest intact works nice, but replacing it will not.