code: private void visitObjectWithSpread(NodeTraversal t, Node obj) {
      checkArgument(obj.isObjectLit());
  
      // Add an empty target object literal so changes made by Object.assign will not affect any other
      // variables.
      Node result =
          astFactory.createObjectDotAssignCall(
              t.getScope(), obj.getJSType(), astFactory.createEmptyObjectLit());
  
      // An indicator whether the current last thing in the param list is an object literal to which
      // properties may be added.  Initialized to null since nothing should be added to the empty
      // object literal in first position of the param list.
      Node trailingObjectLiteral = null;
  
      for (Node child : obj.children()) {
        if (child.isSpread()) {
          // Add the object directly to the param list.
          Node spreaded = child.removeFirstChild();
          result.addChildToBack(spreaded);
  
          // Properties should not be added to the trailing object.
          trailingObjectLiteral = null;
        } else {
          if (trailingObjectLiteral == null) {
            // Add a new object to which properties may be added.
            trailingObjectLiteral = astFactory.createEmptyObjectLit();
            result.addChildToBack(trailingObjectLiteral);
          }
          // Add the property to the object literal.
          trailingObjectLiteral.addChildToBack(child.detach());
        }
      }
  
      result.useSourceInfoIfMissingFromForTree(obj);
      obj.replaceWith(result);
      compiler.reportChangeToEnclosingScope(result);
    }
docs: /*
  Convert '{first: b, c, ...spread, d: e, last}' to:
  
  Object.assign({}, {first:b, c}, spread, {d:e, last});