facebook / jscodeshift

A JavaScript codemod toolkit.
https://jscodeshift.com
MIT License
9.32k stars 481 forks source link

Newlines being unexpectedly removed / reordered #364

Open jefflloyd opened 4 years ago

jefflloyd commented 4 years ago

Hi, all. I'm trying to run jscodeshift to modify Properties of an ObjectExpression. The code I'm running (and the files I'm running it on) are more complex, but here is a simple example to illustrate the problem I'm seeing. Given an input file like:

export default {
  one: "1",
  two: "2",

  three: "3"
}

And a transform:

module.exports = function(fileInfo, api) {
  const j = api.jscodeshift;

  return api.jscodeshift(fileInfo.source)
    .find(j.ObjectExpression)
    .forEach(path => {
      const properties = path.get('properties');

      properties.insertAt(
        0,
        j.property('init', j.identifier("zero"), j.literal("0"))
      );
    })
    .toSource();
}

I would expect the resulting file to look like:

export default {
  zero: "0",
  one: "1",
  two: "2",

  three: "3"
};

But instead, this is the result:

export default {
  zero: "0",
  one: "1",
  two: "2",
  three: "3"
};

The transformation was successful (the "zero" property was added as expected), but the newline between properties "two" and "three" was removed. The newlines are not always just collapsed; with more complicated inputs, newlines are sometimes added between properties that didn't have one before, too. This is important to us, as our developers have separated various properties into groups for ease of development, and the tool is unfortunately messing with those groups and making the diff hard to understand. Ideally, we would expect that whitespace in unaffected areas of the code would be preserved.

Thanks for taking the time to look at this! If you need any additional information, please let me know.

NickHeiner commented 4 years ago

I'm seeing another issue with ObjectPattern where a newline is inserted when I don't expect it. I don't know if it's related to this issue.

alexanderdickson commented 3 years ago

I'm also running into this issue on ObjectExpression. I've tried both calling remove() directly on a property reference and filtering directly the properties object on the node. It seems to happen when a key's value contains a newline, such as a multiline object definition.

This AST Explorer demonstrates the issue.

Source

({
  key1: 'value',
  key2: 'value',
  key3: {
    key: 1
  },
  key4: {
    key: 2
  },
})

Transformer

export default function transform(file, api) {
  const j = api.jscodeshift;
  const { source } = file;
  const root = j(source);

  const obj = root.find(j.ObjectExpression).get(0).parentPath.value;
  obj.properties = obj.properties.filter((_, i) => i % 2) 
  return root.toSource();
}

Output

(({
  key2: 'value',

  key4: {
    key: 2
  }
}))

(Notice that newline appearing above).