benjamn / recast

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

CallExpression with UpdateExpression not being wrapped with parentheses #1362

Closed MeguminSama closed 1 year ago

MeguminSama commented 1 year ago

Take the input var t = (Ae++).toString()

With this (via acorn) we get an AST of

{
      "type": "VariableDeclaration",
      "start": 2,
      "end": 25,
      "declarations": [
        {
          "type": "VariableDeclarator",
          "start": 6,
          "end": 25,
          "id": {
            "type": "Identifier",
            "start": 6,
            "end": 7,
            "name": "t"
          },
          "init": {
            "type": "CallExpression",
            "start": 8,
            "end": 25,
            "callee": {
              "type": "MemberExpression",
              "start": 8,
              "end": 23,
              "object": {
                "type": "UpdateExpression",
                "start": 9,
                "end": 13,
                "operator": "++",
                "prefix": false,
                "argument": {
                  "type": "Identifier",
                  "start": 9,
                  "end": 11,
                  "name": "Ae"
                }
              },
              "property": {
                "type": "Identifier",
                "start": 15,
                "end": 23,
                "name": "toString"
              },
              "computed": false,
              "optional": false
            },
            "arguments": [],
            "optional": false
          }
        }
      ],
      "kind": "var"
    }

If we run this through recast.print, we get var t = Ae++.toString() which is invalid syntax.

It seems to be missing the parentheses.

Tested on recast 0.21.2 and 0.23.4

MeguminSama commented 1 year ago

Turns out acorn has a preserveParens to add a non-standard params value. This fixes recast.print.