diff --git a/formatTest/unit_tests/expected_output/whitespace.re b/formatTest/unit_tests/expected_output/whitespace.re
index 4bebd4149..1b0973c70 100644
--- a/formatTest/unit_tests/expected_output/whitespace.re
+++ b/formatTest/unit_tests/expected_output/whitespace.re
@@ -182,6 +182,152 @@ module EdgeCase = {
let x = 1;
};
+/** Record-like expressions */
+let r = {
+ a: 1,
+
+ b: 2,
+ c: 3,
+};
+
+/* with punning */
+let r = {
+ a,
+
+ b,
+ c,
+};
+
+/* with spread */
+let r = {
+ ...x,
+
+ a: 1,
+
+ b: 2,
+ c: 3,
+};
+
+/* comments */
+let r = {
+ ...x,
+
+ /* a */
+ a: 1,
+
+ /* b */
+ /* c */
+
+ /* d */
+ b: 2,
+ /* e */
+
+ c: 3,
+
+ /* f */
+ d,
+
+ e,
+};
+
+/* string keys */
+let x = {
+ "a": 1,
+
+ "b": 2,
+ "c": 3,
+};
+
+/* string keys punning */
+let x = {
+ "a": a,
+
+ "b": b,
+ "c": c,
+};
+
+/* string keys with spread */
+let x = {
+ ...x,
+
+ "a": 1,
+
+ "b": 2,
+ "c": 3,
+};
+
+/* string keys with comments */
+let x = {
+ ...x,
+
+ /* a */
+ "a": 1,
+
+ /* b */
+ /* c */
+
+ /* d */
+ "b": 2,
+ /* e */
+
+ "c": 3,
+
+ /* f */
+ "d": d,
+
+ "e": e,
+};
+
+let make = _children => {
+ ...component,
+
+ initialState: () => {
+ posts: [],
+ activeRoute:
+ urlToRoute(
+ ReasonReact.Router.dangerouslyGetInitialUrl(),
+ ),
+ },
+
+ didMount: self => {
+ let watcherID =
+ ReasonReact.Router.watchUrl(url =>
+ self.send(
+ ChangeRoute(urlToRoute(url)),
+ )
+ );
+ self.onUnmount(() =>
+ ReasonReact.Router.unwatchUrl(watcherID)
+ );
+ },
+
+ reducer: (action, state) =>
+ switch (action) {
+ | ChangeRoute(activeRoute) =>
+ ReasonReact.Update({
+ ...state,
+ activeRoute,
+ })
+ | FetchCats => ReasonReact.NoUpdate
+ },
+
+ render: ({state: {posts, activeRoute}}) =>
+
+
+ {
+ switch (activeRoute) {
+ | Default =>
+ | Detail(postId) =>
+
+ }
+ }
+
,
+};
+
let f = (a, b) => a + b;
/* this comment sticks at the end */
diff --git a/formatTest/unit_tests/input/whitespace.re b/formatTest/unit_tests/input/whitespace.re
index 7311f9ffa..cc02640a7 100644
--- a/formatTest/unit_tests/input/whitespace.re
+++ b/formatTest/unit_tests/input/whitespace.re
@@ -31,7 +31,7 @@ module Comments = {
/* wow another one below too */
let add = Test.x;
-
+
/* this
is
@@ -187,6 +187,137 @@ module EdgeCase = {
let x = 1;
};
+/** Record-like expressions */
+let r = {
+ a: 1,
+
+ b: 2,
+ c: 3,
+};
+
+/* with punning */
+let r = {
+ a,
+
+ b,
+ c,
+};
+
+/* with spread */
+let r = {
+ ...x,
+
+ a: 1,
+
+ b: 2,
+ c: 3,
+};
+
+/* comments */
+let r = {
+ ...x,
+
+ /* a */
+ a: 1,
+
+ /* b */
+ /* c */
+
+ /* d */
+ b: 2,
+ /* e */
+
+ c: 3,
+
+ /* f */
+ d,
+
+ e,
+};
+
+/* string keys */
+let x = {
+ "a": 1,
+
+ "b": 2,
+ "c": 3,
+};
+
+/* string keys punning */
+let x = {
+ "a",
+
+ "b",
+ "c"
+};
+
+/* string keys with spread */
+let x = {
+ ...x,
+
+ "a": 1,
+
+ "b": 2,
+ "c": 3,
+};
+
+/* string keys with comments */
+let x = {
+ ...x,
+
+ /* a */
+ "a": 1,
+
+ /* b */
+ /* c */
+
+ /* d */
+ "b": 2,
+ /* e */
+
+ "c": 3,
+
+ /* f */
+ "d",
+
+ "e",
+};
+
+let make = _children => {
+ ...component,
+
+ initialState: () => {
+ posts: [],
+ activeRoute: urlToRoute(ReasonReact.Router.dangerouslyGetInitialUrl()),
+ },
+
+ didMount: self => {
+ let watcherID =
+ ReasonReact.Router.watchUrl(url =>
+ self.send(ChangeRoute(urlToRoute(url)))
+ );
+ self.onUnmount(() => ReasonReact.Router.unwatchUrl(watcherID));
+ },
+
+ reducer: (action, state) =>
+ switch (action) {
+ | ChangeRoute(activeRoute) =>
+ ReasonReact.Update({...state, activeRoute})
+ | FetchCats => ReasonReact.NoUpdate
+ },
+
+ render: ({state: {posts, activeRoute}}) =>
+
+
+ {
+ switch (activeRoute) {
+ | Default =>
+ | Detail(postId) =>
+ }
+ }
+
,
+};
+
let f = (a, b) => a + b;
/* this comment sticks at the end */
diff --git a/src/reason-parser/reason_parser.mly b/src/reason-parser/reason_parser.mly
index 705d927ba..14d42b488 100644
--- a/src/reason-parser/reason_parser.mly
+++ b/src/reason-parser/reason_parser.mly
@@ -3582,7 +3582,7 @@ string_literal_expr_maybe_punned_with_comma:
{ let loc = mklocation $startpos $endpos in
let (s, _, _) = $1 in
let lident_lident_loc = mkloc (Lident s) loc in
- let exp = mkexp (Pexp_ident lident_lident_loc) in
+ let exp = mkexp ~loc (Pexp_ident lident_lident_loc) in
(lident_lident_loc, exp)
}
| STRING COLON expr COMMA
@@ -3600,7 +3600,7 @@ string_literal_expr_maybe_punned:
let lident_lident_loc = mkloc (Lident s) loc in
let exp = match $2 with
| Some x -> x
- | None -> mkexp (Pexp_ident lident_lident_loc)
+ | None -> mkexp ~loc (Pexp_ident lident_lident_loc)
in
(lident_lident_loc, exp)
}
diff --git a/src/reason-parser/reason_pprint_ast.ml b/src/reason-parser/reason_pprint_ast.ml
index 81ce1d082..5fc16d9bb 100644
--- a/src/reason-parser/reason_pprint_ast.ml
+++ b/src/reason-parser/reason_pprint_ast.ml
@@ -5734,7 +5734,7 @@ let printer = object(self:'self)
self#wrapCurriedFunctionBinding
~sweet:true ~attachTo:upToColon funToken ~arrow:"=>"
firstArg tl returnedAppTerms
- in source_map ~loc:totalRowLoc theRow
+ in (source_map ~loc:totalRowLoc theRow, totalRowLoc)
in
let rec getRows l =
match l with
@@ -5751,20 +5751,27 @@ let printer = object(self:'self)
| [hd] -> [makeRow hd false]
| _ -> getRows l
)
+ (* This case represents a "spread" being present -> {...x, a: 1, b: 2} *)
| Some withRecord ->
- let firstRow = (
- (* Unclear why "sugar_expr" was special cased hre. *)
- let appTerms = self#unparseExprApplicationItems withRecord in
- formatAttachmentApplication applicationFinalWrapping (Some (false, (atom "..."))) appTerms
- ) in
- source_map ~loc:withRecord.pexp_loc firstRow :: getRows l
+ let firstRow =
+ let row = (
+ (* Unclear why "sugar_expr" was special cased hre. *)
+ let appTerms = self#unparseExprApplicationItems withRecord in
+ formatAttachmentApplication applicationFinalWrapping (Some (false, (atom "..."))) appTerms
+ )
+ in (
+ source_map ~loc:withRecord.pexp_loc row,
+ withRecord.pexp_loc
+ )
+ in
+ firstRow::(getRows l)
in
makeList
~wrap:(lwrap ^ "{" ,"}" ^ rwrap)
~break:(if !forceBreak then Layout.Always else Layout.IfNeed)
~sep:commaTrail
~postSpace:true
- allRows
+ (groupAndPrint ~xf:fst ~getLoc:snd ~comments:self#comments allRows)
method isSeriesOfOpensFollowedByNonSequencyExpression expr =
match (expr.pexp_attributes, expr.pexp_desc) with