@prettier/plugin-php 0.19.2 → 0.19.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/printer.js CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  const {
4
4
  breakParent,
5
- concat,
6
5
  join,
7
6
  line,
8
7
  lineSuffix,
@@ -18,11 +17,8 @@ const {
18
17
  dedentToRoot,
19
18
  } = require("prettier").doc.builders;
20
19
  const { willBreak } = require("prettier").doc.utils;
21
- const {
22
- isNextLineEmptyAfterIndex,
23
- hasNewline,
24
- hasNewlineInRange,
25
- } = require("prettier").util;
20
+ const { isNextLineEmptyAfterIndex, hasNewline, hasNewlineInRange } =
21
+ require("prettier").util;
26
22
  const comments = require("./comments");
27
23
  const pathNeedsParens = require("./needs-parens");
28
24
 
@@ -114,11 +110,11 @@ function genericPrint(path, options, print) {
114
110
  parts.push(hardline);
115
111
  }
116
112
 
117
- return concat(parts);
113
+ return parts;
118
114
  }
119
115
 
120
116
  function printPropertyLookup(path, options, print, nullsafe = false) {
121
- return concat([nullsafe ? "?" : "", "->", path.call(print, "offset")]);
117
+ return [nullsafe ? "?" : "", "->", path.call(print, "offset")];
122
118
  }
123
119
 
124
120
  function printNullsafePropertyLookup(path, options, print) {
@@ -129,12 +125,12 @@ function printStaticLookup(path, options, print) {
129
125
  const node = path.getValue();
130
126
  const needCurly = !["variable", "identifier"].includes(node.offset.kind);
131
127
 
132
- return concat([
128
+ return [
133
129
  "::",
134
130
  needCurly ? "{" : "",
135
131
  path.call(print, "offset"),
136
132
  needCurly ? "}" : "",
137
- ]);
133
+ ];
138
134
  }
139
135
 
140
136
  function printOffsetLookup(path, options, print) {
@@ -143,20 +139,16 @@ function printOffsetLookup(path, options, print) {
143
139
  (node.offset && node.offset.kind === "number") ||
144
140
  getAncestorNode(path, "encapsed");
145
141
 
146
- return concat([
142
+ return [
147
143
  "[",
148
144
  node.offset
149
- ? group(
150
- concat([
151
- indent(
152
- concat([shouldInline ? "" : softline, path.call(print, "offset")])
153
- ),
154
- shouldInline ? "" : softline,
155
- ])
156
- )
145
+ ? group([
146
+ indent([shouldInline ? "" : softline, path.call(print, "offset")]),
147
+ shouldInline ? "" : softline,
148
+ ])
157
149
  : "",
158
150
  "]",
159
- ]);
151
+ ];
160
152
  }
161
153
 
162
154
  // We detect calls on member expressions specially to format a
@@ -232,14 +224,14 @@ function printMemberChain(path, options, print) {
232
224
  ) {
233
225
  printedNodes.unshift({
234
226
  node,
235
- printed: concat([
227
+ printed: [
236
228
  comments.printAllComments(
237
229
  path,
238
- () => concat([printArgumentsList(path, options, print)]),
230
+ () => printArgumentsList(path, options, print),
239
231
  options
240
232
  ),
241
233
  shouldInsertEmptyLineAfter(node) ? hardline : "",
242
- ]),
234
+ ],
243
235
  });
244
236
  path.call((what) => traverse(what), "what");
245
237
  } else if (isLookupNode(node)) {
@@ -294,8 +286,8 @@ function printMemberChain(path, options, print) {
294
286
  ) &&
295
287
  printedNodes[i - 1].needsParens
296
288
  ) {
297
- printedNodes[0].printed = concat(["(", printedNodes[0].printed]);
298
- printedNodes[i - 1].printed = concat([printedNodes[i - 1].printed, ")"]);
289
+ printedNodes[0].printed = ["(", printedNodes[0].printed];
290
+ printedNodes[i - 1].printed = [printedNodes[i - 1].printed, ")"];
299
291
  }
300
292
  }
301
293
 
@@ -462,7 +454,7 @@ function printMemberChain(path, options, print) {
462
454
  }
463
455
  }
464
456
 
465
- return concat(result);
457
+ return result;
466
458
  }
467
459
 
468
460
  function printIndentedGroup(groups) {
@@ -470,13 +462,11 @@ function printMemberChain(path, options, print) {
470
462
  return "";
471
463
  }
472
464
 
473
- return indent(
474
- group(concat([hardline, join(hardline, groups.map(printGroup))]))
475
- );
465
+ return indent(group([hardline, join(hardline, groups.map(printGroup))]));
476
466
  }
477
467
 
478
468
  const printedGroups = groups.map(printGroup);
479
- const oneLine = concat(printedGroups);
469
+ const oneLine = printedGroups;
480
470
 
481
471
  // Indicates how many we should merge
482
472
  //
@@ -490,9 +480,7 @@ function printMemberChain(path, options, print) {
490
480
  // ->method()
491
481
  // ->otherMethod();
492
482
  const cutoff = shouldMerge ? 3 : 2;
493
- const flatGroups = groups
494
- .slice(0, cutoff)
495
- .reduce((res, group) => res.concat(group), []);
483
+ const flatGroups = groups.slice(0, cutoff).flat();
496
484
 
497
485
  const hasComment =
498
486
  flatGroups
@@ -521,12 +509,12 @@ function printMemberChain(path, options, print) {
521
509
  lastNodeBeforeIndent.kind !== "call" &&
522
510
  shouldInsertEmptyLineAfter(lastNodeBeforeIndent);
523
511
 
524
- const expanded = concat([
512
+ const expanded = [
525
513
  printGroup(groups[0]),
526
- shouldMerge ? concat(groups.slice(1, 2).map(printGroup)) : "",
514
+ shouldMerge ? groups.slice(1, 2).map(printGroup) : "",
527
515
  shouldHaveEmptyLineBeforeIndent ? hardline : "",
528
516
  printIndentedGroup(groups.slice(shouldMerge ? 2 : 1)),
529
- ]);
517
+ ];
530
518
 
531
519
  const callExpressionCount = printedNodes.filter(
532
520
  (tuple) => tuple.node.kind === "call"
@@ -545,13 +533,13 @@ function printMemberChain(path, options, print) {
545
533
  return group(expanded);
546
534
  }
547
535
 
548
- return concat([
536
+ return [
549
537
  // We only need to check `oneLine` because if `expanded` is chosen
550
538
  // that means that the parent group has already been broken
551
539
  // naturally
552
540
  willBreak(oneLine) || shouldHaveEmptyLineBeforeIndent ? breakParent : "",
553
541
  conditionalGroup([oneLine, expanded]),
554
- ]);
542
+ ];
555
543
  }
556
544
 
557
545
  function couldGroupArg(arg) {
@@ -598,11 +586,11 @@ function printArgumentsList(path, options, print, argumentsKey = "arguments") {
598
586
  const args = path.getValue()[argumentsKey];
599
587
 
600
588
  if (args.length === 0) {
601
- return concat([
589
+ return [
602
590
  "(",
603
591
  comments.printDanglingComments(path, options, /* sameIndent */ true),
604
592
  ")",
605
- ]);
593
+ ];
606
594
  }
607
595
 
608
596
  let anyArgEmptyLine = false;
@@ -626,7 +614,7 @@ function printArgumentsList(path, options, print, argumentsKey = "arguments") {
626
614
  parts.push(",", line);
627
615
  }
628
616
 
629
- return concat(parts);
617
+ return parts;
630
618
  }, argumentsKey);
631
619
 
632
620
  const node = path.getValue();
@@ -639,25 +627,17 @@ function printArgumentsList(path, options, print, argumentsKey = "arguments") {
639
627
  ["function", "closure", "method", "arrowfunc", "attribute"].includes(
640
628
  node.kind
641
629
  ))
642
- ? indent(
643
- concat([
644
- lastArg && shouldPrintHardlineBeforeTrailingComma(lastArg)
645
- ? hardline
646
- : "",
647
- ",",
648
- ])
649
- )
630
+ ? indent([
631
+ lastArg && shouldPrintHardlineBeforeTrailingComma(lastArg)
632
+ ? hardline
633
+ : "",
634
+ ",",
635
+ ])
650
636
  : "";
651
637
 
652
638
  function allArgsBrokenOut() {
653
639
  return group(
654
- concat([
655
- "(",
656
- indent(concat([line, concat(printedArguments)])),
657
- maybeTrailingComma,
658
- line,
659
- ")",
660
- ]),
640
+ ["(", indent([line, ...printedArguments]), maybeTrailingComma, line, ")"],
661
641
  { shouldBreak: true }
662
642
  );
663
643
  }
@@ -678,28 +658,28 @@ function printArgumentsList(path, options, print, argumentsKey = "arguments") {
678
658
  path.each((argPath) => {
679
659
  if (shouldGroupFirst && i === 0) {
680
660
  printedExpanded = [
681
- concat([
682
- argPath.call((p) => print(p, { expandFirstArg: true })),
683
- printedArguments.length > 1 ? "," : "",
684
- hasEmptyLineFollowingFirstArg ? hardline : line,
685
- hasEmptyLineFollowingFirstArg ? hardline : "",
686
- ]),
687
- ].concat(printedArguments.slice(1));
661
+ argPath.call((p) => print(p, { expandFirstArg: true })),
662
+ printedArguments.length > 1 ? "," : "",
663
+ hasEmptyLineFollowingFirstArg ? hardline : line,
664
+ hasEmptyLineFollowingFirstArg ? hardline : "",
665
+ printedArguments.slice(1),
666
+ ];
688
667
  }
689
668
 
690
669
  if (shouldGroupLast && i === args.length - 1) {
691
- printedExpanded = printedArguments
692
- .slice(0, -1)
693
- .concat(argPath.call((p) => print(p, { expandLastArg: true })));
670
+ printedExpanded = [
671
+ ...printedArguments.slice(0, -1),
672
+ argPath.call((p) => print(p, { expandLastArg: true })),
673
+ ];
694
674
  }
695
675
 
696
676
  i++;
697
677
  }, argumentsKey);
698
678
 
699
679
  const somePrintedArgumentsWillBreak = printedArguments.some(willBreak);
700
- const simpleConcat = concat(["(", concat(printedExpanded), ")"]);
680
+ const simpleConcat = ["(", ...printedExpanded, ")"];
701
681
 
702
- return concat([
682
+ return [
703
683
  somePrintedArgumentsWillBreak ? breakParent : "",
704
684
  conditionalGroup(
705
685
  [
@@ -707,44 +687,44 @@ function printArgumentsList(path, options, print, argumentsKey = "arguments") {
707
687
  ? simpleConcat
708
688
  : ifBreak(allArgsBrokenOut(), simpleConcat),
709
689
  shouldGroupFirst
710
- ? concat([
690
+ ? [
711
691
  "(",
712
692
  group(printedExpanded[0], { shouldBreak: true }),
713
- concat(printedExpanded.slice(1)),
693
+ ...printedExpanded.slice(1),
714
694
  ")",
715
- ])
716
- : concat([
695
+ ]
696
+ : [
717
697
  "(",
718
- concat(printedArguments.slice(0, -1)),
698
+ ...printedArguments.slice(0, -1),
719
699
  group(getLast(printedExpanded), {
720
700
  shouldBreak: true,
721
701
  }),
722
702
  ")",
723
- ]),
703
+ ],
724
704
  group(
725
- concat([
705
+ [
726
706
  "(",
727
- indent(concat([line, concat(printedArguments)])),
707
+ indent([line, ...printedArguments]),
728
708
  ifBreak(maybeTrailingComma),
729
709
  line,
730
710
  ")",
731
- ]),
711
+ ],
732
712
  { shouldBreak: true }
733
713
  ),
734
714
  ],
735
715
  { shouldBreak }
736
716
  ),
737
- ]);
717
+ ];
738
718
  }
739
719
 
740
720
  return group(
741
- concat([
721
+ [
742
722
  "(",
743
- indent(concat([softline, concat(printedArguments)])),
723
+ indent([softline, ...printedArguments]),
744
724
  ifBreak(maybeTrailingComma),
745
725
  softline,
746
726
  ")",
747
- ]),
727
+ ],
748
728
  {
749
729
  shouldBreak: printedArguments.some(willBreak) || anyArgEmptyLine,
750
730
  }
@@ -809,8 +789,8 @@ function printBinaryExpression(
809
789
  const shouldInline = shouldInlineLogicalExpression(node);
810
790
 
811
791
  const right = shouldInline
812
- ? concat([node.type, " ", path.call(print, "right")])
813
- : concat([node.type, line, path.call(print, "right")]);
792
+ ? [node.type, " ", path.call(print, "right")]
793
+ : [node.type, line, path.call(print, "right")];
814
794
 
815
795
  // If there's only a single binary expression, we want to create a group
816
796
  // in order to avoid having a small right part like -1 be on its own line.
@@ -837,7 +817,7 @@ function printBinaryExpression(
837
817
  // the other ones since we don't call the normal print on bin,
838
818
  // only for the left and right parts
839
819
  if (isNested && node.comments) {
840
- parts = comments.printAllComments(path, () => concat(parts), options);
820
+ parts = comments.printAllComments(path, () => parts, options);
841
821
  }
842
822
  } else {
843
823
  // Our stopping case. Simply print the node normally.
@@ -888,7 +868,7 @@ function printArrayItems(path, options, print) {
888
868
  let separatorParts = [];
889
869
 
890
870
  path.each((childPath) => {
891
- printedElements.push(concat(separatorParts));
871
+ printedElements.push(separatorParts);
892
872
  printedElements.push(group(print(childPath)));
893
873
 
894
874
  separatorParts = [",", line];
@@ -901,7 +881,7 @@ function printArrayItems(path, options, print) {
901
881
  }
902
882
  }, "items");
903
883
 
904
- return concat(printedElements);
884
+ return printedElements;
905
885
  }
906
886
 
907
887
  // Wrap parts into groups by indexes.
@@ -925,19 +905,17 @@ function wrapPartsIntoGroups(parts, indexes) {
925
905
 
926
906
  return indexes.reduce((accumulator, index) => {
927
907
  const { start, end, alignment, before, after } = index;
928
- const printedPartsForGrouping = concat([
908
+ const printedPartsForGrouping = [
929
909
  before || "",
930
- concat(parts.slice(start, end)),
910
+ ...parts.slice(start, end),
931
911
  after || "",
932
- ]);
912
+ ];
933
913
  const newArray = accumulator.concat(
934
914
  parts.slice(lastEnd, start),
935
915
  alignment
936
916
  ? dedentToRoot(
937
917
  group(
938
- concat([
939
- align(new Array(alignment).join(" "), printedPartsForGrouping),
940
- ])
918
+ align(new Array(alignment).join(" "), printedPartsForGrouping)
941
919
  )
942
920
  )
943
921
  : group(printedPartsForGrouping),
@@ -972,14 +950,14 @@ function printLines(path, options, print, childrenAttribute = "children") {
972
950
  ? !isFirstChildrenInlineNode(path)
973
951
  : nextNode && nextNode.kind !== "inline");
974
952
 
975
- let printed = concat([
953
+ let printed = [
976
954
  printedPath,
977
955
  canPrintBlankLine ? hardline : "",
978
956
  canPrintBlankLine &&
979
957
  isNextLineEmpty(options.originalText, childNode, options)
980
958
  ? hardline
981
959
  : "",
982
- ]);
960
+ ];
983
961
 
984
962
  const isFirstNode = index === 0;
985
963
  const isLastNode = children.length - 1 === index;
@@ -1040,7 +1018,7 @@ function printLines(path, options, print, childrenAttribute = "children") {
1040
1018
  : "<?php";
1041
1019
  const beforeInline =
1042
1020
  childNode.leadingComments && childNode.leadingComments.length
1043
- ? concat([
1021
+ ? [
1044
1022
  isFirstNode && node.kind !== "namespace" && !isBlockNestedNode
1045
1023
  ? "<?php"
1046
1024
  : "",
@@ -1048,30 +1026,29 @@ function printLines(path, options, print, childrenAttribute = "children") {
1048
1026
  comments.printComments(childNode.leadingComments, options),
1049
1027
  hardline,
1050
1028
  "?>",
1051
- ])
1029
+ ]
1052
1030
  : isProgramLikeNode(node) && isFirstNode && node.kind !== "namespace"
1053
1031
  ? ""
1054
- : concat([beforeCloseTagInlineNode, "?>"]);
1032
+ : [beforeCloseTagInlineNode, "?>"];
1055
1033
 
1056
1034
  const nextV = path.getNode(index + 1);
1057
1035
  const skipLastComment = nextV && nextV.children && nextV.children.length;
1058
1036
 
1059
1037
  const afterInline =
1060
1038
  childNode.comments && childNode.comments.length
1061
- ? concat([
1039
+ ? [
1062
1040
  openTag,
1063
1041
  hardline,
1064
1042
  skipLastComment
1065
1043
  ? comments.printComments(childNode.comments, options)
1066
1044
  : "",
1067
1045
  hardline,
1068
- skipLastComment ? "?>" : "",
1069
- ])
1046
+ ]
1070
1047
  : isProgramLikeNode(node) && isLastNode
1071
1048
  ? ""
1072
- : concat([openTag, " "]);
1049
+ : [openTag, " "];
1073
1050
 
1074
- printed = concat([beforeInline, printed, afterInline]);
1051
+ printed = [beforeInline, printed, afterInline];
1075
1052
  }
1076
1053
 
1077
1054
  parts.push(printed);
@@ -1087,73 +1064,74 @@ function printLines(path, options, print, childrenAttribute = "children") {
1087
1064
 
1088
1065
  if (hasStartTag) {
1089
1066
  const between = options.originalText.trim().match(/^<\?(php|=)(\s+)?\S/);
1090
- const afterOpenTag = concat([
1067
+ const afterOpenTag = [
1091
1068
  between && between[2] && between[2].includes("\n")
1092
- ? concat([
1093
- hardline,
1094
- between[2].split("\n").length > 2 ? hardline : "",
1095
- ])
1069
+ ? [hardline, between[2].split("\n").length > 2 ? hardline : ""]
1096
1070
  : " ",
1097
1071
  node.comments ? comments.printComments(node.comments, options) : "",
1098
- ]);
1072
+ ];
1099
1073
 
1100
1074
  const shortEcho =
1101
1075
  firstNode && firstNode.kind === "echo" && firstNode.shortForm;
1102
- parts.push(concat([shortEcho ? "<?=" : "<?php", afterOpenTag]));
1076
+ parts.push([shortEcho ? "<?=" : "<?php", afterOpenTag]);
1103
1077
  }
1104
1078
 
1105
- parts.push(concat(wrappedParts));
1079
+ parts.push(wrappedParts);
1106
1080
 
1107
- const hasEndTag = options.originalText.trim().endsWith("?>");
1081
+ const hasEndTag = /\?>\n?$/.test(options.originalText);
1108
1082
 
1109
1083
  if (hasEndTag) {
1110
1084
  const lastNode = getLast(node.children);
1111
1085
  const beforeCloseTag = lastNode
1112
- ? concat([
1086
+ ? [
1113
1087
  hasNewlineInRange(
1114
1088
  options.originalText.trimEnd(),
1115
1089
  options.locEnd(lastNode),
1116
1090
  options.locEnd(node)
1117
1091
  )
1118
- ? hardline
1092
+ ? !(
1093
+ lastNode.kind === "inline" &&
1094
+ lastNode.comments &&
1095
+ lastNode.comments.length
1096
+ )
1097
+ ? hardline
1098
+ : ""
1119
1099
  : " ",
1120
1100
  isNextLineEmpty(options.originalText, lastNode, options)
1121
1101
  ? hardline
1122
1102
  : "",
1123
- ])
1103
+ ]
1124
1104
  : node.comments
1125
1105
  ? hardline
1126
1106
  : "";
1127
1107
 
1128
- parts.push(lineSuffix(concat([beforeCloseTag, "?>"])));
1108
+ parts.push(lineSuffix([beforeCloseTag, "?>"]));
1129
1109
  }
1130
1110
 
1131
- return concat(parts);
1111
+ return parts;
1132
1112
  }
1133
1113
 
1134
- return concat(wrappedParts);
1114
+ return wrappedParts;
1135
1115
  }
1136
1116
 
1137
1117
  function printStatements(path, options, print, childrenAttribute) {
1138
- return concat(
1139
- path.map((childPath) => {
1140
- const parts = [];
1118
+ return path.map((childPath) => {
1119
+ const parts = [];
1141
1120
 
1142
- parts.push(print(childPath));
1121
+ parts.push(print(childPath));
1143
1122
 
1144
- if (!isLastStatement(childPath)) {
1145
- parts.push(hardline);
1123
+ if (!isLastStatement(childPath)) {
1124
+ parts.push(hardline);
1146
1125
 
1147
- if (
1148
- isNextLineEmpty(options.originalText, childPath.getValue(), options)
1149
- ) {
1150
- parts.push(hardline);
1151
- }
1126
+ if (
1127
+ isNextLineEmpty(options.originalText, childPath.getValue(), options)
1128
+ ) {
1129
+ parts.push(hardline);
1152
1130
  }
1131
+ }
1153
1132
 
1154
- return concat(parts);
1155
- }, childrenAttribute)
1156
- );
1133
+ return parts;
1134
+ }, childrenAttribute);
1157
1135
  }
1158
1136
 
1159
1137
  function printClassPart(
@@ -1166,46 +1144,40 @@ function printClassPart(
1166
1144
  ) {
1167
1145
  const node = path.getValue();
1168
1146
  const printedBeforePart = hasDanglingComments(node[part])
1169
- ? concat([
1147
+ ? [
1170
1148
  hardline,
1171
1149
  path.call(
1172
1150
  (partPath) => comments.printDanglingComments(partPath, options, true),
1173
1151
  part
1174
1152
  ),
1175
1153
  hardline,
1176
- ])
1154
+ ]
1177
1155
  : beforePart;
1178
1156
  const printedPartItems = Array.isArray(node[part])
1179
1157
  ? group(
1180
- concat([
1181
- join(
1182
- ",",
1183
- path.map((itemPartPath) => {
1184
- const printedPart = print(itemPartPath);
1185
- // Check if any of the implements nodes have comments
1186
- return hasDanglingComments(itemPartPath.getValue())
1187
- ? concat([
1188
- hardline,
1189
- comments.printDanglingComments(itemPartPath, options, true),
1190
- hardline,
1191
- printedPart,
1192
- ])
1193
- : concat([afterPart, printedPart]);
1194
- }, part)
1195
- ),
1196
- ])
1158
+ join(
1159
+ ",",
1160
+ path.map((itemPartPath) => {
1161
+ const printedPart = print(itemPartPath);
1162
+ // Check if any of the implements nodes have comments
1163
+ return hasDanglingComments(itemPartPath.getValue())
1164
+ ? [
1165
+ hardline,
1166
+ comments.printDanglingComments(itemPartPath, options, true),
1167
+ hardline,
1168
+ printedPart,
1169
+ ]
1170
+ : [afterPart, printedPart];
1171
+ }, part)
1172
+ )
1197
1173
  )
1198
- : concat([afterPart, path.call(print, part)]);
1199
-
1200
- return indent(
1201
- concat([
1202
- printedBeforePart,
1203
- part,
1204
- willBreak(printedBeforePart)
1205
- ? indent(printedPartItems)
1206
- : printedPartItems,
1207
- ])
1208
- );
1174
+ : [afterPart, path.call(print, part)];
1175
+
1176
+ return indent([
1177
+ printedBeforePart,
1178
+ part,
1179
+ willBreak(printedBeforePart) ? indent(printedPartItems) : printedPartItems,
1180
+ ]);
1209
1181
  }
1210
1182
 
1211
1183
  function printAttrs(path, options, print, { inline = false } = {}) {
@@ -1228,24 +1200,22 @@ function printAttrs(path, options, print, { inline = false } = {}) {
1228
1200
  if (attrNode.args.length > 0) {
1229
1201
  attrStmt.push(printArgumentsList(attrPath, options, print, "args"));
1230
1202
  }
1231
- attrGroup.push(group(concat(attrStmt)));
1203
+ attrGroup.push(group(attrStmt));
1232
1204
  }, "attrs");
1233
1205
  allAttrs.push(
1234
- group(
1235
- concat([
1236
- indent(concat(attrGroup)),
1237
- ifBreak(shouldPrintComma(options, "8.0") ? "," : ""),
1238
- softline,
1239
- "]",
1240
- inline ? ifBreak(softline, " ") : "",
1241
- ])
1242
- )
1206
+ group([
1207
+ indent(attrGroup),
1208
+ ifBreak(shouldPrintComma(options, "8.0") ? "," : ""),
1209
+ softline,
1210
+ "]",
1211
+ inline ? ifBreak(softline, " ") : "",
1212
+ ])
1243
1213
  );
1244
1214
  }, "attrGroups");
1245
1215
  if (allAttrs.length === 0) {
1246
1216
  return [];
1247
1217
  }
1248
- return [concat([...allAttrs, inline ? "" : hardline])];
1218
+ return [...allAttrs, inline ? "" : hardline];
1249
1219
  }
1250
1220
 
1251
1221
  function printClass(path, options, print) {
@@ -1254,6 +1224,10 @@ function printClass(path, options, print) {
1254
1224
  const attrs = printAttrs(path, options, print, { inline: isAnonymousClass });
1255
1225
  const declaration = isAnonymousClass ? [] : [...attrs];
1256
1226
 
1227
+ if (node.isReadonly) {
1228
+ declaration.push("readonly ");
1229
+ }
1230
+
1257
1231
  if (node.isFinal) {
1258
1232
  declaration.push("final ");
1259
1233
  }
@@ -1278,15 +1252,15 @@ function printClass(path, options, print) {
1278
1252
  declaration.push(
1279
1253
  conditionalGroup(
1280
1254
  [
1281
- concat([
1255
+ [
1282
1256
  printClassPart(path, options, print, "extends"),
1283
1257
  printClassPart(path, options, print, "implements"),
1284
- ]),
1285
- concat([
1258
+ ],
1259
+ [
1286
1260
  printClassPart(path, options, print, "extends"),
1287
1261
  printClassPart(path, options, print, "implements", " ", hardline),
1288
- ]),
1289
- concat([
1262
+ ],
1263
+ [
1290
1264
  printClassPart(path, options, print, "extends", hardline, " "),
1291
1265
  printClassPart(
1292
1266
  path,
@@ -1296,7 +1270,7 @@ function printClass(path, options, print) {
1296
1270
  hardline,
1297
1271
  node.implements.length > 1 ? hardline : " "
1298
1272
  ),
1299
- ]),
1273
+ ],
1300
1274
  ],
1301
1275
  {
1302
1276
  shouldBreak: hasDanglingComments(node.extends),
@@ -1339,33 +1313,29 @@ function printClass(path, options, print) {
1339
1313
  }
1340
1314
  }
1341
1315
 
1342
- const printedDeclaration = group(
1343
- concat([
1344
- group(concat(declaration)),
1345
- shouldPrintHardlineForOpenBrace(options)
1346
- ? isAnonymousClass
1347
- ? line
1348
- : hardline
1349
- : " ",
1350
- ])
1351
- );
1316
+ const printedDeclaration = group([
1317
+ group(declaration),
1318
+ shouldPrintHardlineForOpenBrace(options)
1319
+ ? isAnonymousClass
1320
+ ? line
1321
+ : hardline
1322
+ : " ",
1323
+ ]);
1352
1324
 
1353
1325
  const hasEmptyClassBody =
1354
1326
  node.body && node.body.length === 0 && !hasDanglingComments(node);
1355
- const printedBody = concat([
1327
+ const printedBody = [
1356
1328
  "{",
1357
- indent(
1358
- concat([
1359
- hasEmptyClassBody ? "" : hardline,
1360
- printStatements(path, options, print, "body"),
1361
- ])
1362
- ),
1329
+ indent([
1330
+ hasEmptyClassBody ? "" : hardline,
1331
+ printStatements(path, options, print, "body"),
1332
+ ]),
1363
1333
  comments.printDanglingComments(path, options, true),
1364
1334
  isAnonymousClass && hasEmptyClassBody ? softline : hardline,
1365
1335
  "}",
1366
- ]);
1336
+ ];
1367
1337
 
1368
- return concat([printedDeclaration, printedBody]);
1338
+ return [printedDeclaration, printedBody];
1369
1339
  }
1370
1340
 
1371
1341
  function printFunction(path, options, print) {
@@ -1405,76 +1375,72 @@ function printFunction(path, options, print) {
1405
1375
 
1406
1376
  if (node.uses && node.uses.length > 0) {
1407
1377
  declaration.push(
1408
- group(concat([" use ", printArgumentsList(path, options, print, "uses")]))
1378
+ group([" use ", printArgumentsList(path, options, print, "uses")])
1409
1379
  );
1410
1380
  }
1411
1381
 
1412
1382
  if (node.type) {
1413
- declaration.push(
1414
- concat([
1415
- ": ",
1416
- hasDanglingComments(node.type)
1417
- ? concat([
1418
- path.call(
1419
- (typePath) =>
1420
- comments.printDanglingComments(typePath, options, true),
1421
- "type"
1422
- ),
1423
- " ",
1424
- ])
1425
- : "",
1426
- node.nullable ? "?" : "",
1427
- path.call(print, "type"),
1428
- ])
1429
- );
1383
+ declaration.push([
1384
+ ": ",
1385
+ hasDanglingComments(node.type)
1386
+ ? [
1387
+ path.call(
1388
+ (typePath) =>
1389
+ comments.printDanglingComments(typePath, options, true),
1390
+ "type"
1391
+ ),
1392
+ " ",
1393
+ ]
1394
+ : "",
1395
+ node.nullable ? "?" : "",
1396
+ path.call(print, "type"),
1397
+ ]);
1430
1398
  }
1431
1399
 
1432
- const printedDeclaration = concat(declaration);
1400
+ const printedDeclaration = declaration;
1433
1401
 
1434
1402
  if (!node.body) {
1435
- return concat([...declAttrs, printedDeclaration]);
1403
+ return [...declAttrs, printedDeclaration];
1436
1404
  }
1437
1405
 
1438
1406
  const isClosure = node.kind === "closure";
1439
- const printedBody = concat([
1407
+ const printedBody = [
1440
1408
  "{",
1441
- indent(
1442
- concat([hasEmptyBody(path) ? "" : hardline, path.call(print, "body")])
1443
- ),
1409
+ indent([hasEmptyBody(path) ? "" : hardline, path.call(print, "body")]),
1444
1410
  isClosure && hasEmptyBody(path) ? "" : hardline,
1445
1411
  "}",
1446
- ]);
1412
+ ];
1447
1413
 
1448
1414
  if (isClosure) {
1449
- return concat([...declAttrs, printedDeclaration, " ", printedBody]);
1415
+ return [...declAttrs, printedDeclaration, " ", printedBody];
1450
1416
  }
1451
1417
 
1452
1418
  if (node.arguments.length === 0) {
1453
- return concat([
1419
+ return [
1454
1420
  ...declAttrs,
1455
1421
  printedDeclaration,
1456
1422
  shouldPrintHardlineForOpenBrace(options) ? hardline : " ",
1457
1423
  printedBody,
1458
- ]);
1424
+ ];
1459
1425
  }
1460
1426
 
1461
1427
  const willBreakDeclaration = declaration.some(willBreak);
1462
1428
 
1463
1429
  if (willBreakDeclaration) {
1464
- return concat([printedDeclaration, " ", printedBody]);
1430
+ return [printedDeclaration, " ", printedBody];
1465
1431
  }
1466
1432
 
1467
- return concat([
1433
+ return [
1468
1434
  ...declAttrs,
1469
1435
  conditionalGroup([
1470
- concat([
1436
+ [
1471
1437
  printedDeclaration,
1472
1438
  shouldPrintHardlineForOpenBrace(options) ? hardline : " ",
1473
1439
  printedBody,
1474
- ]),
1475
- concat([printedDeclaration, " ", printedBody]),
1440
+ ],
1441
+ [printedDeclaration, " ", printedBody],
1476
1442
  ]),
1477
- ]);
1443
+ ];
1478
1444
  }
1479
1445
 
1480
1446
  function printBodyControlStructure(
@@ -1491,32 +1457,30 @@ function printBodyControlStructure(
1491
1457
 
1492
1458
  const printedBody = path.call(print, bodyProperty);
1493
1459
 
1494
- return concat([
1460
+ return [
1495
1461
  node.shortForm ? ":" : " {",
1496
1462
  indent(
1497
- concat([
1498
- node[bodyProperty].kind !== "block" ||
1463
+ node[bodyProperty].kind !== "block" ||
1499
1464
  (node[bodyProperty].children &&
1500
1465
  node[bodyProperty].children.length > 0) ||
1501
1466
  (node[bodyProperty].comments && node[bodyProperty].comments.length > 0)
1502
- ? concat([
1503
- shouldPrintHardLineAfterStartInControlStructure(path)
1504
- ? node.kind === "switch"
1505
- ? " "
1506
- : ""
1507
- : hardline,
1508
- printedBody,
1509
- ])
1510
- : "",
1511
- ])
1467
+ ? [
1468
+ shouldPrintHardLineAfterStartInControlStructure(path)
1469
+ ? node.kind === "switch"
1470
+ ? " "
1471
+ : ""
1472
+ : hardline,
1473
+ printedBody,
1474
+ ]
1475
+ : ""
1512
1476
  ),
1513
1477
  node.kind === "if" && bodyProperty === "body"
1514
1478
  ? ""
1515
- : concat([
1479
+ : [
1516
1480
  shouldPrintHardLineBeforeEndInControlStructure(path) ? hardline : "",
1517
- node.shortForm ? concat(["end", node.kind, ";"]) : "}",
1518
- ]),
1519
- ]);
1481
+ node.shortForm ? ["end", node.kind, ";"] : "}",
1482
+ ],
1483
+ ];
1520
1484
  }
1521
1485
 
1522
1486
  function printAssignment(
@@ -1540,7 +1504,7 @@ function printAssignment(
1540
1504
  options
1541
1505
  );
1542
1506
 
1543
- return group(concat([printedLeft, operator, printed]));
1507
+ return group([printedLeft, operator, printed]);
1544
1508
  }
1545
1509
 
1546
1510
  function isLookupNodeChain(node) {
@@ -1567,7 +1531,7 @@ function printAssignmentRight(
1567
1531
  if (
1568
1532
  comments.hasLeadingOwnLineComment(options.originalText, rightNode, options)
1569
1533
  ) {
1570
- return indent(concat([hardline, ref, printedRight]));
1534
+ return indent([hardline, ref, printedRight]);
1571
1535
  }
1572
1536
 
1573
1537
  const pureRightNode = rightNode.kind === "cast" ? rightNode.expr : rightNode;
@@ -1587,10 +1551,10 @@ function printAssignmentRight(
1587
1551
  isLookupNodeChain(pureRightNode)));
1588
1552
 
1589
1553
  if (canBreak) {
1590
- return group(indent(concat([line, ref, printedRight])));
1554
+ return group(indent([line, ref, printedRight]));
1591
1555
  }
1592
1556
 
1593
- return concat([" ", ref, printedRight]);
1557
+ return [" ", ref, printedRight];
1594
1558
  }
1595
1559
 
1596
1560
  function needsHardlineAfterDanglingComment(node) {
@@ -1621,12 +1585,9 @@ function isStringOnItsOwnLine(node, text, options) {
1621
1585
 
1622
1586
  function printComposedTypes(path, print, glue) {
1623
1587
  return group(
1624
- concat(
1625
- path.map(
1626
- (uPath, i) =>
1627
- concat(i === 0 ? [path.call(print)] : [glue, path.call(print)]),
1628
- "types"
1629
- )
1588
+ path.map(
1589
+ (uPath, i) => (i === 0 ? [path.call(print)] : [glue, path.call(print)]),
1590
+ "types"
1630
1591
  )
1631
1592
  );
1632
1593
  }
@@ -1636,76 +1597,74 @@ function printNode(path, options, print) {
1636
1597
 
1637
1598
  switch (node.kind) {
1638
1599
  case "program": {
1639
- return group(
1640
- concat([
1641
- printLines(path, options, print),
1642
- comments.printDanglingComments(
1643
- path,
1644
- options,
1645
- /* sameIndent */ true,
1646
- (c) => !c.printed
1647
- ),
1648
- ])
1649
- );
1600
+ return group([
1601
+ printLines(path, options, print),
1602
+ comments.printDanglingComments(
1603
+ path,
1604
+ options,
1605
+ /* sameIndent */ true,
1606
+ (c) => !c.printed
1607
+ ),
1608
+ ]);
1650
1609
  }
1651
1610
  case "expressionstatement":
1652
1611
  return path.call(print, "expression");
1653
1612
  case "block":
1654
- return concat([
1613
+ return [
1655
1614
  printLines(path, options, print),
1656
1615
  comments.printDanglingComments(path, options, true),
1657
- ]);
1616
+ ];
1658
1617
  case "declare": {
1659
1618
  const printDeclareArguments = (path) => {
1660
1619
  return join(
1661
1620
  ", ",
1662
- path.map((directive) => concat([print(directive)]), "directives")
1621
+ path.map((directive) => print(directive), "directives")
1663
1622
  );
1664
1623
  };
1665
1624
 
1666
1625
  if (["block", "short"].includes(node.mode)) {
1667
- return concat([
1626
+ return [
1668
1627
  "declare(",
1669
1628
  printDeclareArguments(path),
1670
1629
  ")",
1671
1630
  node.mode === "block" ? " {" : ":",
1672
1631
  node.children.length > 0
1673
- ? indent(concat([hardline, printLines(path, options, print)]))
1632
+ ? indent([hardline, printLines(path, options, print)])
1674
1633
  : "",
1675
1634
  comments.printDanglingComments(path, options),
1676
1635
  hardline,
1677
1636
  node.mode === "block" ? "}" : "enddeclare;",
1678
- ]);
1637
+ ];
1679
1638
  }
1680
1639
 
1681
1640
  const nextNode = getNextNode(path, node);
1682
1641
 
1683
- return concat([
1642
+ return [
1684
1643
  "declare(",
1685
1644
  printDeclareArguments(path),
1686
1645
  ")",
1687
1646
  nextNode && nextNode.kind === "inline" ? "" : ";",
1688
- ]);
1647
+ ];
1689
1648
  }
1690
1649
  case "declaredirective":
1691
- return concat([path.call(print, "key"), "=", path.call(print, "value")]);
1650
+ return [path.call(print, "key"), "=", path.call(print, "value")];
1692
1651
  case "namespace":
1693
- return concat([
1652
+ return [
1694
1653
  "namespace ",
1695
1654
  node.name && typeof node.name === "string"
1696
- ? concat([node.name, node.withBrackets ? " " : ""])
1655
+ ? [node.name, node.withBrackets ? " " : ""]
1697
1656
  : "",
1698
1657
  node.withBrackets ? "{" : ";",
1699
1658
  hasDanglingComments(node)
1700
- ? concat([" ", comments.printDanglingComments(path, options, true)])
1659
+ ? [" ", comments.printDanglingComments(path, options, true)]
1701
1660
  : "",
1702
1661
  node.children.length > 0
1703
1662
  ? node.withBrackets
1704
- ? indent(concat([hardline, printLines(path, options, print)]))
1705
- : concat([
1663
+ ? indent([hardline, printLines(path, options, print)])
1664
+ : [
1706
1665
  node.children[0].kind === "inline"
1707
1666
  ? ""
1708
- : concat([
1667
+ : [
1709
1668
  hardline,
1710
1669
  isNextLineEmptyAfterNamespace(
1711
1670
  options.originalText,
@@ -1714,121 +1673,109 @@ function printNode(path, options, print) {
1714
1673
  )
1715
1674
  ? hardline
1716
1675
  : "",
1717
- ]),
1676
+ ],
1718
1677
  printLines(path, options, print),
1719
- ])
1678
+ ]
1720
1679
  : "",
1721
- node.withBrackets ? concat([hardline, "}"]) : "",
1722
- ]);
1680
+ node.withBrackets ? [hardline, "}"] : "",
1681
+ ];
1723
1682
  case "usegroup":
1724
- return group(
1725
- concat([
1726
- "use ",
1727
- node.type ? concat([node.type, " "]) : "",
1728
- indent(
1729
- concat([
1730
- node.name
1731
- ? concat([
1732
- maybeStripLeadingSlashFromUse(node.name),
1733
- "\\{",
1734
- softline,
1735
- ])
1736
- : "",
1737
- join(
1738
- concat([",", line]),
1739
- path.map((item) => concat([print(item)]), "items")
1740
- ),
1741
- ])
1742
- ),
1683
+ return group([
1684
+ "use ",
1685
+ node.type ? [node.type, " "] : "",
1686
+ indent([
1743
1687
  node.name
1744
- ? concat([
1745
- ifBreak(shouldPrintComma(options, "7.2") ? "," : ""),
1746
- softline,
1747
- "}",
1748
- ])
1688
+ ? [maybeStripLeadingSlashFromUse(node.name), "\\{", softline]
1749
1689
  : "",
1750
- ])
1751
- );
1690
+ join(
1691
+ [",", line],
1692
+ path.map((item) => print(item), "items")
1693
+ ),
1694
+ ]),
1695
+ node.name
1696
+ ? [
1697
+ ifBreak(shouldPrintComma(options, "7.2") ? "," : ""),
1698
+ softline,
1699
+ "}",
1700
+ ]
1701
+ : "",
1702
+ ]);
1752
1703
  case "useitem":
1753
- return concat([
1754
- node.type ? concat([node.type, " "]) : "",
1704
+ return [
1705
+ node.type ? [node.type, " "] : "",
1755
1706
  maybeStripLeadingSlashFromUse(node.name),
1756
1707
  hasDanglingComments(node)
1757
- ? concat([" ", comments.printDanglingComments(path, options, true)])
1708
+ ? [" ", comments.printDanglingComments(path, options, true)]
1758
1709
  : "",
1759
- node.alias ? concat([" as ", path.call(print, "alias")]) : "",
1760
- ]);
1710
+ node.alias ? [" as ", path.call(print, "alias")] : "",
1711
+ ];
1761
1712
  case "class":
1762
1713
  case "enum":
1763
1714
  case "interface":
1764
1715
  case "trait":
1765
1716
  return printClass(path, options, print);
1766
1717
  case "traitprecedence":
1767
- return concat([
1718
+ return [
1768
1719
  path.call(print, "trait"),
1769
1720
  "::",
1770
1721
  path.call(print, "method"),
1771
1722
  " insteadof ",
1772
1723
  join(", ", path.map(print, "instead")),
1773
- ]);
1724
+ ];
1774
1725
  case "traitalias":
1775
- return concat([
1776
- node.trait ? concat([path.call(print, "trait"), "::"]) : "",
1726
+ return [
1727
+ node.trait ? [path.call(print, "trait"), "::"] : "",
1777
1728
  node.method ? path.call(print, "method") : "",
1778
1729
  " as ",
1779
1730
  join(" ", [
1780
1731
  ...(node.visibility ? [node.visibility] : []),
1781
1732
  ...(node.as ? [path.call(print, "as")] : []),
1782
1733
  ]),
1783
- ]);
1734
+ ];
1784
1735
  case "traituse":
1785
- return group(
1786
- concat([
1787
- "use ",
1788
- indent(group(join(concat([",", line]), path.map(print, "traits")))),
1789
- node.adaptations
1790
- ? concat([
1791
- " {",
1792
- node.adaptations.length > 0
1793
- ? concat([
1794
- indent(
1795
- concat([
1796
- hardline,
1797
- printStatements(path, options, print, "adaptations"),
1798
- ])
1799
- ),
1736
+ return group([
1737
+ "use ",
1738
+ indent(group(join([",", line], path.map(print, "traits")))),
1739
+ node.adaptations
1740
+ ? [
1741
+ " {",
1742
+ node.adaptations.length > 0
1743
+ ? [
1744
+ indent([
1800
1745
  hardline,
1801
- ])
1802
- : hasDanglingComments(node)
1803
- ? concat([
1804
- line,
1805
- comments.printDanglingComments(path, options, true),
1806
- line,
1807
- ])
1808
- : "",
1809
- "}",
1810
- ])
1811
- : "",
1812
- ])
1813
- );
1746
+ printStatements(path, options, print, "adaptations"),
1747
+ ]),
1748
+ hardline,
1749
+ ]
1750
+ : hasDanglingComments(node)
1751
+ ? [
1752
+ line,
1753
+ comments.printDanglingComments(path, options, true),
1754
+ line,
1755
+ ]
1756
+ : "",
1757
+ "}",
1758
+ ]
1759
+ : "",
1760
+ ]);
1814
1761
  case "function":
1815
1762
  case "closure":
1816
1763
  case "method":
1817
1764
  return printFunction(path, options, print);
1818
1765
  case "arrowfunc":
1819
- return concat([
1766
+ return [
1820
1767
  node.parenthesizedExpression ? "(" : "",
1821
1768
  ...printAttrs(path, options, print, { inline: true }),
1822
1769
  node.isStatic ? "static " : "",
1823
1770
  "fn",
1824
1771
  printArgumentsList(path, options, print),
1825
1772
  node.type
1826
- ? concat([": ", node.nullable ? "?" : "", path.call(print, "type")])
1773
+ ? [": ", node.nullable ? "?" : "", path.call(print, "type")]
1827
1774
  : "",
1828
1775
  " => ",
1829
1776
  path.call(print, "body"),
1830
1777
  node.parenthesizedExpression ? ")" : "",
1831
- ]);
1778
+ ];
1832
1779
  case "parameter": {
1833
1780
  let promoted = "";
1834
1781
  if (node.flags === 1) {
@@ -1838,28 +1785,51 @@ function printNode(path, options, print) {
1838
1785
  } else if (node.flags === 4) {
1839
1786
  promoted = "private ";
1840
1787
  }
1841
- const name = concat([
1788
+ const name = [
1842
1789
  ...printAttrs(path, options, print, { inline: true }),
1843
1790
  promoted,
1844
1791
  node.readonly ? "readonly " : "",
1845
1792
  node.nullable ? "?" : "",
1846
- node.type ? concat([path.call(print, "type"), " "]) : "",
1793
+ node.type ? [path.call(print, "type"), " "] : "",
1847
1794
  node.byref ? "&" : "",
1848
1795
  node.variadic ? "..." : "",
1849
1796
  "$",
1850
1797
  path.call(print, "name"),
1851
- ]);
1798
+ ];
1852
1799
 
1853
1800
  if (node.value) {
1854
- return group(
1855
- concat([
1856
- name,
1857
- // see handleFunctionParameter() in ./comments.js - since there's
1858
- // no node to attach comments that fall in between the parameter name
1859
- // and value, we store them as dangling comments
1860
- hasDanglingComments(node) ? " " : "",
1861
- comments.printDanglingComments(path, options, true),
1862
- concat([
1801
+ return group([
1802
+ name,
1803
+ // see handleFunctionParameter() in ./comments.js - since there's
1804
+ // no node to attach comments that fall in between the parameter name
1805
+ // and value, we store them as dangling comments
1806
+ hasDanglingComments(node) ? " " : "",
1807
+ comments.printDanglingComments(path, options, true),
1808
+ " =",
1809
+ printAssignmentRight(
1810
+ node.name,
1811
+ node.value,
1812
+ path.call(print, "value"),
1813
+ false,
1814
+ options
1815
+ ),
1816
+ ]);
1817
+ }
1818
+
1819
+ return name;
1820
+ }
1821
+ case "variadic":
1822
+ return ["...", path.call(print, "what")];
1823
+ case "property":
1824
+ return group([
1825
+ node.readonly ? "readonly " : "",
1826
+ node.type
1827
+ ? [node.nullable ? "?" : "", path.call(print, "type"), " "]
1828
+ : "",
1829
+ "$",
1830
+ path.call(print, "name"),
1831
+ node.value
1832
+ ? [
1863
1833
  " =",
1864
1834
  printAssignmentRight(
1865
1835
  node.name,
@@ -1868,38 +1838,9 @@ function printNode(path, options, print) {
1868
1838
  false,
1869
1839
  options
1870
1840
  ),
1871
- ]),
1872
- ])
1873
- );
1874
- }
1875
-
1876
- return name;
1877
- }
1878
- case "variadic":
1879
- return concat(["...", path.call(print, "what")]);
1880
- case "property":
1881
- return group(
1882
- concat([
1883
- node.readonly ? "readonly " : "",
1884
- node.type
1885
- ? concat([node.nullable ? "?" : "", path.call(print, "type"), " "])
1886
- : "",
1887
- "$",
1888
- path.call(print, "name"),
1889
- node.value
1890
- ? concat([
1891
- " =",
1892
- printAssignmentRight(
1893
- node.name,
1894
- node.value,
1895
- path.call(print, "value"),
1896
- false,
1897
- options
1898
- ),
1899
- ])
1900
- : "",
1901
- ])
1902
- );
1841
+ ]
1842
+ : "",
1843
+ ]);
1903
1844
  case "propertystatement": {
1904
1845
  const attrs = [];
1905
1846
  path.map(
@@ -1923,40 +1864,27 @@ function printNode(path, options, print) {
1923
1864
 
1924
1865
  const hasVisibility = node.visibility || node.visibility === null;
1925
1866
 
1926
- return group(
1927
- concat([
1928
- ...attrs,
1929
- hasVisibility
1930
- ? concat([node.visibility === null ? "var" : node.visibility, ""])
1931
- : "",
1932
- node.isStatic ? concat([hasVisibility ? " " : "", "static"]) : "",
1933
- firstProperty ? concat([" ", firstProperty]) : "",
1934
- indent(
1935
- concat(
1936
- printed
1937
- .slice(1)
1938
- .map((p) => concat([",", hasValue ? hardline : line, p]))
1939
- )
1940
- ),
1941
- ])
1942
- );
1867
+ return group([
1868
+ ...attrs,
1869
+ hasVisibility
1870
+ ? [node.visibility === null ? "var" : node.visibility, ""]
1871
+ : "",
1872
+ node.isStatic ? [hasVisibility ? " " : "", "static"] : "",
1873
+ firstProperty ? [" ", firstProperty] : "",
1874
+ indent(
1875
+ printed.slice(1).map((p) => [",", hasValue ? hardline : line, p])
1876
+ ),
1877
+ ]);
1943
1878
  }
1944
1879
  case "if": {
1945
1880
  const parts = [];
1946
1881
  const body = printBodyControlStructure(path, options, print, "body");
1947
- const opening = group(
1948
- concat([
1949
- "if (",
1950
- group(
1951
- concat([
1952
- indent(concat([softline, path.call(print, "test")])),
1953
- softline,
1954
- ])
1955
- ),
1956
- ")",
1957
- body,
1958
- ])
1959
- );
1882
+ const opening = group([
1883
+ "if (",
1884
+ group([indent([softline, path.call(print, "test")]), softline]),
1885
+ ")",
1886
+ body,
1887
+ ]);
1960
1888
 
1961
1889
  parts.push(
1962
1890
  opening,
@@ -1997,37 +1925,25 @@ function printNode(path, options, print) {
1997
1925
  parts.push(node.body ? (node.shortForm ? "endif;" : "}") : "");
1998
1926
  }
1999
1927
 
2000
- return concat(parts);
1928
+ return parts;
2001
1929
  }
2002
1930
  case "do":
2003
- return concat([
1931
+ return [
2004
1932
  "do",
2005
1933
  printBodyControlStructure(path, options, print, "body"),
2006
1934
  " while (",
2007
- group(
2008
- concat([
2009
- indent(concat([softline, path.call(print, "test")])),
2010
- softline,
2011
- ])
2012
- ),
1935
+ group([indent([softline, path.call(print, "test")]), softline]),
2013
1936
  ")",
2014
- ]);
1937
+ ];
2015
1938
  case "while":
2016
1939
  case "switch":
2017
- return group(
2018
- concat([
2019
- node.kind,
2020
- " (",
2021
- group(
2022
- concat([
2023
- indent(concat([softline, path.call(print, "test")])),
2024
- softline,
2025
- ])
2026
- ),
2027
- ")",
2028
- printBodyControlStructure(path, options, print, "body"),
2029
- ])
2030
- );
1940
+ return group([
1941
+ node.kind,
1942
+ " (",
1943
+ group([indent([softline, path.call(print, "test")]), softline]),
1944
+ ")",
1945
+ printBodyControlStructure(path, options, print, "body"),
1946
+ ]);
2031
1947
  case "for": {
2032
1948
  const body = printBodyControlStructure(path, options, print, "body");
2033
1949
 
@@ -2039,49 +1955,33 @@ function printNode(path, options, print) {
2039
1955
  options,
2040
1956
  /* sameLine */ true
2041
1957
  );
2042
- const printedComments = dangling ? concat([dangling, softline]) : "";
1958
+ const printedComments = dangling ? [dangling, softline] : "";
2043
1959
 
2044
1960
  if (!node.init.length && !node.test.length && !node.increment.length) {
2045
- return concat([printedComments, group(concat(["for (;;)", body]))]);
1961
+ return [printedComments, group(["for (;;)", body])];
2046
1962
  }
2047
1963
 
2048
- return concat([
1964
+ return [
2049
1965
  printedComments,
2050
- group(
2051
- concat([
2052
- "for (",
2053
- group(
2054
- concat([
2055
- indent(
2056
- concat([
2057
- softline,
2058
- group(
2059
- concat([
2060
- join(concat([",", line]), path.map(print, "init")),
2061
- ])
2062
- ),
2063
- ";",
2064
- line,
2065
- group(
2066
- concat([
2067
- join(concat([",", line]), path.map(print, "test")),
2068
- ])
2069
- ),
2070
- ";",
2071
- line,
2072
- group(
2073
- join(concat([",", line]), path.map(print, "increment"))
2074
- ),
2075
- ])
2076
- ),
2077
- softline,
2078
- ])
2079
- ),
2080
- ")",
2081
- body,
2082
- ])
2083
- ),
2084
- ]);
1966
+ group([
1967
+ "for (",
1968
+ group([
1969
+ indent([
1970
+ softline,
1971
+ group(join([",", line], path.map(print, "init"))),
1972
+ ";",
1973
+ line,
1974
+ group(join([",", line], path.map(print, "test"))),
1975
+ ";",
1976
+ line,
1977
+ group(join([",", line], path.map(print, "increment"))),
1978
+ ]),
1979
+ softline,
1980
+ ]),
1981
+ ")",
1982
+ body,
1983
+ ]),
1984
+ ];
2085
1985
  }
2086
1986
  case "foreach": {
2087
1987
  const body = printBodyControlStructure(path, options, print, "body");
@@ -2094,41 +1994,35 @@ function printNode(path, options, print) {
2094
1994
  options,
2095
1995
  /* sameLine */ true
2096
1996
  );
2097
- const printedComments = dangling ? concat([dangling, softline]) : "";
1997
+ const printedComments = dangling ? [dangling, softline] : "";
2098
1998
 
2099
- return concat([
1999
+ return [
2100
2000
  printedComments,
2101
- group(
2102
- concat([
2103
- "foreach (",
2104
- group(
2105
- concat([
2106
- indent(
2107
- concat([
2108
- softline,
2109
- path.call(print, "source"),
2110
- line,
2111
- "as ",
2112
- group(
2113
- node.key
2114
- ? indent(
2115
- join(concat([" =>", line]), [
2116
- path.call(print, "key"),
2117
- path.call(print, "value"),
2118
- ])
2119
- )
2120
- : path.call(print, "value")
2121
- ),
2122
- ])
2123
- ),
2124
- softline,
2125
- ])
2126
- ),
2127
- ")",
2128
- body,
2129
- ])
2130
- ),
2131
- ]);
2001
+ group([
2002
+ "foreach (",
2003
+ group([
2004
+ indent([
2005
+ softline,
2006
+ path.call(print, "source"),
2007
+ line,
2008
+ "as ",
2009
+ group(
2010
+ node.key
2011
+ ? indent(
2012
+ join(
2013
+ [" =>", line],
2014
+ [path.call(print, "key"), path.call(print, "value")]
2015
+ )
2016
+ )
2017
+ : path.call(print, "value")
2018
+ ),
2019
+ ]),
2020
+ softline,
2021
+ ]),
2022
+ ")",
2023
+ body,
2024
+ ]),
2025
+ ];
2132
2026
  }
2133
2027
  case "try": {
2134
2028
  const parts = [];
@@ -2139,7 +2033,7 @@ function printNode(path, options, print) {
2139
2033
  );
2140
2034
 
2141
2035
  if (node.catches) {
2142
- parts.push(concat(path.map(print, "catches")));
2036
+ parts.push(path.map(print, "catches"));
2143
2037
  }
2144
2038
 
2145
2039
  if (node.always) {
@@ -2149,49 +2043,47 @@ function printNode(path, options, print) {
2149
2043
  );
2150
2044
  }
2151
2045
 
2152
- return concat(parts);
2046
+ return parts;
2153
2047
  }
2154
2048
  case "catch": {
2155
- return concat([
2049
+ return [
2156
2050
  " catch",
2157
2051
  node.what
2158
- ? concat([
2052
+ ? [
2159
2053
  " (",
2160
2054
  join(" | ", path.map(print, "what")),
2161
- node.variable ? concat([" ", path.call(print, "variable")]) : "",
2055
+ node.variable ? [" ", path.call(print, "variable")] : "",
2162
2056
  ")",
2163
- ])
2057
+ ]
2164
2058
  : "",
2165
2059
  printBodyControlStructure(path, options, print, "body"),
2166
- ]);
2060
+ ];
2167
2061
  }
2168
2062
  case "case":
2169
- return concat([
2063
+ return [
2170
2064
  node.test
2171
- ? concat([
2065
+ ? [
2172
2066
  "case ",
2173
2067
  node.test.comments
2174
2068
  ? indent(path.call(print, "test"))
2175
2069
  : path.call(print, "test"),
2176
2070
  ":",
2177
- ])
2071
+ ]
2178
2072
  : "default:",
2179
2073
  node.body
2180
2074
  ? node.body.children && node.body.children.length
2181
- ? indent(
2182
- concat([
2183
- isFirstChildrenInlineNode(path) ? "" : hardline,
2184
- path.call(print, "body"),
2185
- ])
2186
- )
2075
+ ? indent([
2076
+ isFirstChildrenInlineNode(path) ? "" : hardline,
2077
+ path.call(print, "body"),
2078
+ ])
2187
2079
  : ""
2188
2080
  : "",
2189
- ]);
2081
+ ];
2190
2082
  case "break":
2191
2083
  case "continue":
2192
2084
  if (node.level) {
2193
2085
  if (node.level.kind === "number" && node.level.value !== "1") {
2194
- return concat([`${node.kind} `, path.call(print, "level")]);
2086
+ return [`${node.kind} `, path.call(print, "level")];
2195
2087
  }
2196
2088
 
2197
2089
  return node.kind;
@@ -2204,10 +2096,12 @@ function printNode(path, options, print) {
2204
2096
  node.arguments.length === 1 &&
2205
2097
  isStringOnItsOwnLine(node.arguments[0], options.originalText, options)
2206
2098
  ) {
2207
- return concat([
2099
+ return [
2208
2100
  path.call(print, "what"),
2209
- concat(["(", join(", ", path.map(print, "arguments")), ")"]),
2210
- ]);
2101
+ "(",
2102
+ join(", ", path.map(print, "arguments")),
2103
+ ")",
2104
+ ];
2211
2105
  }
2212
2106
 
2213
2107
  // chain: Call (*LookupNode (Call (*LookupNode (...))))
@@ -2215,10 +2109,10 @@ function printNode(path, options, print) {
2215
2109
  return printMemberChain(path, options, print);
2216
2110
  }
2217
2111
 
2218
- return concat([
2112
+ return [
2219
2113
  path.call(print, "what"),
2220
2114
  printArgumentsList(path, options, print),
2221
- ]);
2115
+ ];
2222
2116
  }
2223
2117
  case "new": {
2224
2118
  const isAnonymousClassNode =
@@ -2230,14 +2124,14 @@ function printNode(path, options, print) {
2230
2124
  node.arguments.length === 1 &&
2231
2125
  isStringOnItsOwnLine(node.arguments[0], options.originalText, options)
2232
2126
  ) {
2233
- return concat([
2127
+ return [
2234
2128
  "new ",
2235
2129
  ...path.call(printAttrs, "what"),
2236
2130
  path.call(print, "what"),
2237
2131
  "(",
2238
2132
  join(", ", path.map(print, "arguments")),
2239
2133
  ")",
2240
- ]);
2134
+ ];
2241
2135
  }
2242
2136
 
2243
2137
  const parts = [];
@@ -2248,10 +2142,7 @@ function printNode(path, options, print) {
2248
2142
  parts.push(
2249
2143
  node.what.leadingComments &&
2250
2144
  node.what.leadingComments[0].kind === "commentblock"
2251
- ? concat([
2252
- comments.printComments(node.what.leadingComments, options),
2253
- " ",
2254
- ])
2145
+ ? [comments.printComments(node.what.leadingComments, options), " "]
2255
2146
  : "",
2256
2147
  ...path.call(
2257
2148
  (pa) => printAttrs(pa, options, print, { inline: true }),
@@ -2259,31 +2150,31 @@ function printNode(path, options, print) {
2259
2150
  ),
2260
2151
  "class",
2261
2152
  node.arguments.length > 0
2262
- ? concat([" ", printArgumentsList(path, options, print)])
2153
+ ? [" ", printArgumentsList(path, options, print)]
2263
2154
  : "",
2264
2155
  group(path.call(print, "what"))
2265
2156
  );
2266
2157
  } else {
2267
2158
  const isExpression = ["call", "offsetlookup"].includes(node.what.kind);
2268
- const printed = concat([
2159
+ const printed = [
2269
2160
  isExpression ? "(" : "",
2270
2161
  path.call(print, "what"),
2271
2162
  isExpression ? ")" : "",
2272
2163
  printArgumentsList(path, options, print),
2273
- ]);
2164
+ ];
2274
2165
 
2275
2166
  parts.push(hasLeadingComment(node.what) ? indent(printed) : printed);
2276
2167
  }
2277
2168
 
2278
- return concat(parts);
2169
+ return parts;
2279
2170
  }
2280
2171
  case "clone":
2281
- return concat([
2172
+ return [
2282
2173
  "clone ",
2283
2174
  node.what.comments
2284
2175
  ? indent(path.call(print, "what"))
2285
2176
  : path.call(print, "what"),
2286
- ]);
2177
+ ];
2287
2178
  case "propertylookup":
2288
2179
  case "nullsafepropertylookup":
2289
2180
  case "staticlookup":
@@ -2313,92 +2204,74 @@ function printNode(path, options, print) {
2313
2204
  parent &&
2314
2205
  !isLookupNode(parent));
2315
2206
 
2316
- return concat([
2207
+ return [
2317
2208
  path.call(print, "what"),
2318
2209
  shouldInline
2319
2210
  ? printLookupNodes(path, options, print)
2320
- : group(
2321
- indent(concat([softline, printLookupNodes(path, options, print)]))
2322
- ),
2323
- ]);
2211
+ : group(indent([softline, printLookupNodes(path, options, print)])),
2212
+ ];
2324
2213
  }
2325
2214
  case "exit":
2326
- return group(
2327
- concat([
2328
- node.useDie ? "die" : "exit",
2329
- "(",
2330
- node.expression
2331
- ? isStringOnItsOwnLine(
2332
- node.expression,
2333
- options.originalText,
2334
- options
2335
- )
2336
- ? path.call(print, "expression")
2337
- : concat([
2338
- indent(concat([softline, path.call(print, "expression")])),
2339
- softline,
2340
- ])
2341
- : comments.printDanglingComments(path, options),
2342
- ")",
2343
- ])
2344
- );
2215
+ return group([
2216
+ node.useDie ? "die" : "exit",
2217
+ "(",
2218
+ node.expression
2219
+ ? isStringOnItsOwnLine(node.expression, options.originalText, options)
2220
+ ? path.call(print, "expression")
2221
+ : [indent([softline, path.call(print, "expression")]), softline]
2222
+ : comments.printDanglingComments(path, options),
2223
+ ")",
2224
+ ]);
2345
2225
  case "global":
2346
- return group(
2347
- concat([
2348
- "global ",
2349
- indent(concat([join(concat([",", line]), path.map(print, "items"))])),
2350
- ])
2351
- );
2226
+ return group([
2227
+ "global ",
2228
+ indent(join([",", line], path.map(print, "items"))),
2229
+ ]);
2352
2230
  case "include":
2353
- return concat([
2231
+ return [
2354
2232
  node.require ? "require" : "include",
2355
2233
  node.once ? "_once" : "",
2356
2234
  " ",
2357
2235
  node.target.comments
2358
2236
  ? indent(path.call(print, "target"))
2359
2237
  : path.call(print, "target"),
2360
- ]);
2238
+ ];
2361
2239
  case "label":
2362
- return concat([path.call(print, "name"), ":"]);
2240
+ return [path.call(print, "name"), ":"];
2363
2241
  case "goto":
2364
- return concat(["goto ", path.call(print, "label")]);
2242
+ return ["goto ", path.call(print, "label")];
2365
2243
  case "throw":
2366
- return concat([
2244
+ return [
2367
2245
  "throw ",
2368
2246
  node.what.comments
2369
2247
  ? indent(path.call(print, "what"))
2370
2248
  : path.call(print, "what"),
2371
- ]);
2249
+ ];
2372
2250
  case "silent":
2373
- return concat(["@", path.call(print, "expr")]);
2251
+ return ["@", path.call(print, "expr")];
2374
2252
  case "halt":
2375
- return concat([
2253
+ return [
2376
2254
  hasDanglingComments(node)
2377
- ? concat([
2255
+ ? [
2378
2256
  comments.printDanglingComments(
2379
2257
  path,
2380
2258
  options,
2381
2259
  /* sameIndent */ true
2382
2260
  ),
2383
2261
  hardline,
2384
- ])
2262
+ ]
2385
2263
  : "",
2386
2264
  "__halt_compiler();",
2387
2265
  node.after,
2388
- ]);
2266
+ ];
2389
2267
  case "eval":
2390
- return group(
2391
- concat([
2392
- "eval(",
2393
- isStringOnItsOwnLine(node.source, options.originalText, options)
2394
- ? path.call(print, "source")
2395
- : concat([
2396
- indent(concat([softline, path.call(print, "source")])),
2397
- softline,
2398
- ]),
2399
- ")",
2400
- ])
2401
- );
2268
+ return group([
2269
+ "eval(",
2270
+ isStringOnItsOwnLine(node.source, options.originalText, options)
2271
+ ? path.call(print, "source")
2272
+ : [indent([softline, path.call(print, "source")]), softline],
2273
+ ")",
2274
+ ]);
2402
2275
  case "echo": {
2403
2276
  const printedArguments = path.map((childPath) => {
2404
2277
  return print(childPath);
@@ -2415,23 +2288,19 @@ function printNode(path, options, print) {
2415
2288
  : dedent(printedArguments[0]);
2416
2289
  }
2417
2290
 
2418
- return group(
2419
- concat([
2420
- node.shortForm ? "" : "echo ",
2421
- firstVariable ? firstVariable : "",
2422
- indent(
2423
- concat(printedArguments.slice(1).map((p) => concat([",", line, p])))
2424
- ),
2425
- ])
2426
- );
2291
+ return group([
2292
+ node.shortForm ? "" : "echo ",
2293
+ firstVariable ? firstVariable : "",
2294
+ indent(printedArguments.slice(1).map((p) => [",", line, p])),
2295
+ ]);
2427
2296
  }
2428
2297
  case "print": {
2429
- return concat([
2298
+ return [
2430
2299
  "print ",
2431
2300
  node.expression.comments
2432
2301
  ? indent(path.call(print, "expression"))
2433
2302
  : path.call(print, "expression"),
2434
- ]);
2303
+ ];
2435
2304
  }
2436
2305
  case "return": {
2437
2306
  const parts = [];
@@ -2451,25 +2320,21 @@ function printNode(path, options, print) {
2451
2320
  );
2452
2321
  }
2453
2322
 
2454
- return concat(parts);
2323
+ return parts;
2455
2324
  }
2456
2325
  case "isset":
2457
2326
  case "unset":
2458
- return group(
2459
- concat([
2460
- node.kind,
2461
- printArgumentsList(path, options, print, "variables"),
2462
- ])
2463
- );
2327
+ return group([
2328
+ node.kind,
2329
+ printArgumentsList(path, options, print, "variables"),
2330
+ ]);
2464
2331
  case "empty":
2465
- return group(
2466
- concat([
2467
- "empty(",
2468
- indent(concat([softline, path.call(print, "expression")])),
2469
- softline,
2470
- ")",
2471
- ])
2472
- );
2332
+ return group([
2333
+ "empty(",
2334
+ indent([softline, path.call(print, "expression")]),
2335
+ softline,
2336
+ ")",
2337
+ ]);
2473
2338
  case "variable": {
2474
2339
  const parent = path.getParentNode();
2475
2340
  const parentParent = path.getParentNode(1);
@@ -2488,13 +2353,13 @@ function printNode(path, options, print) {
2488
2353
  const openCurly = node.curly ? "{" : "";
2489
2354
  const closeCurly = node.curly ? "}" : "";
2490
2355
 
2491
- return concat([
2356
+ return [
2492
2357
  ampersand,
2493
2358
  dollar,
2494
2359
  openCurly,
2495
2360
  path.call(print, "name"),
2496
2361
  closeCurly,
2497
- ]);
2362
+ ];
2498
2363
  }
2499
2364
  case "constantstatement":
2500
2365
  case "classconstant": {
@@ -2510,17 +2375,13 @@ function printNode(path, options, print) {
2510
2375
  firstVariable = indent(printed[0]);
2511
2376
  }
2512
2377
 
2513
- return group(
2514
- concat([
2515
- ...attrs,
2516
- node.visibility ? concat([node.visibility, " "]) : "",
2517
- "const",
2518
- firstVariable ? concat([" ", firstVariable]) : "",
2519
- indent(
2520
- concat(printed.slice(1).map((p) => concat([",", hardline, p])))
2521
- ),
2522
- ])
2523
- );
2378
+ return group([
2379
+ ...attrs,
2380
+ node.visibility ? [node.visibility, " "] : "",
2381
+ "const",
2382
+ firstVariable ? [" ", firstVariable] : "",
2383
+ indent(printed.slice(1).map((p) => [",", hardline, p])),
2384
+ ]);
2524
2385
  }
2525
2386
  case "constant":
2526
2387
  return printAssignment(
@@ -2548,19 +2409,13 @@ function printNode(path, options, print) {
2548
2409
  firstVariable = indent(printed[0]);
2549
2410
  }
2550
2411
 
2551
- return group(
2552
- concat([
2553
- "static",
2554
- firstVariable ? concat([" ", firstVariable]) : "",
2555
- indent(
2556
- concat(
2557
- printed
2558
- .slice(1)
2559
- .map((p) => concat([",", hasValue ? hardline : line, p]))
2560
- )
2561
- ),
2562
- ])
2563
- );
2412
+ return group([
2413
+ "static",
2414
+ firstVariable ? [" ", firstVariable] : "",
2415
+ indent(
2416
+ printed.slice(1).map((p) => [",", hasValue ? hardline : line, p])
2417
+ ),
2418
+ ]);
2564
2419
  }
2565
2420
  case "staticvariable": {
2566
2421
  return printAssignment(
@@ -2579,22 +2434,20 @@ function printNode(path, options, print) {
2579
2434
  (node.kind === "array" && isMinVersion(options.phpVersion, "5.4")) ||
2580
2435
  (node.kind === "list" &&
2581
2436
  (node.shortForm || isMinVersion(options.phpVersion, "7.1")));
2582
- const open = useShortForm ? "[" : concat([node.kind, "("]);
2437
+ const open = useShortForm ? "[" : [node.kind, "("];
2583
2438
  const close = useShortForm ? "]" : ")";
2584
2439
 
2585
2440
  if (node.items.length === 0) {
2586
2441
  if (!hasDanglingComments(node)) {
2587
- return concat([open, close]);
2442
+ return [open, close];
2588
2443
  }
2589
2444
 
2590
- return group(
2591
- concat([
2592
- open,
2593
- comments.printDanglingComments(path, options),
2594
- softline,
2595
- close,
2596
- ])
2597
- );
2445
+ return group([
2446
+ open,
2447
+ comments.printDanglingComments(path, options),
2448
+ softline,
2449
+ close,
2450
+ ]);
2598
2451
  }
2599
2452
 
2600
2453
  const lastElem = getLast(node.items);
@@ -2625,24 +2478,24 @@ function printNode(path, options, print) {
2625
2478
  );
2626
2479
 
2627
2480
  return group(
2628
- concat([
2481
+ [
2629
2482
  open,
2630
- indent(concat([softline, printArrayItems(path, options, print)])),
2483
+ indent([softline, printArrayItems(path, options, print)]),
2631
2484
  needsForcedTrailingComma ? "," : "",
2632
2485
  ifBreak(
2633
2486
  !needsForcedTrailingComma && shouldPrintComma(options, "5.0")
2634
- ? concat([
2487
+ ? [
2635
2488
  lastElem && shouldPrintHardlineBeforeTrailingComma(lastElem)
2636
2489
  ? hardline
2637
2490
  : "",
2638
2491
  ",",
2639
- ])
2492
+ ]
2640
2493
  : ""
2641
2494
  ),
2642
2495
  comments.printDanglingComments(path, options, true),
2643
2496
  softline,
2644
2497
  close,
2645
- ]),
2498
+ ],
2646
2499
  { shouldBreak }
2647
2500
  );
2648
2501
  }
@@ -2659,44 +2512,44 @@ function printNode(path, options, print) {
2659
2512
  ref,
2660
2513
  options
2661
2514
  )
2662
- : concat([ref, unpack, path.call(print, "value")]);
2515
+ : [ref, unpack, path.call(print, "value")];
2663
2516
  }
2664
2517
  case "yield": {
2665
- const printedKeyAndValue = concat([
2666
- node.key ? concat([path.call(print, "key"), " => "]) : "",
2518
+ const printedKeyAndValue = [
2519
+ node.key ? [path.call(print, "key"), " => "] : "",
2667
2520
  path.call(print, "value"),
2668
- ]);
2521
+ ];
2669
2522
 
2670
- return concat([
2523
+ return [
2671
2524
  "yield",
2672
2525
  node.key || node.value ? " " : "",
2673
2526
  node.value && node.value.comments
2674
2527
  ? indent(printedKeyAndValue)
2675
2528
  : printedKeyAndValue,
2676
- ]);
2529
+ ];
2677
2530
  }
2678
2531
  case "yieldfrom":
2679
- return concat([
2532
+ return [
2680
2533
  "yield from ",
2681
2534
  node.value.comments
2682
2535
  ? indent(path.call(print, "value"))
2683
2536
  : path.call(print, "value"),
2684
- ]);
2537
+ ];
2685
2538
  case "unary":
2686
- return concat([node.type, path.call(print, "what")]);
2539
+ return [node.type, path.call(print, "what")];
2687
2540
  case "pre":
2688
- return concat([node.type + node.type, path.call(print, "what")]);
2541
+ return [node.type + node.type, path.call(print, "what")];
2689
2542
  case "post":
2690
- return concat([path.call(print, "what"), node.type + node.type]);
2543
+ return [path.call(print, "what"), node.type + node.type];
2691
2544
  case "cast":
2692
- return concat([
2545
+ return [
2693
2546
  "(",
2694
2547
  node.type,
2695
2548
  ") ",
2696
2549
  node.expr.comments
2697
2550
  ? indent(path.call(print, "expr"))
2698
2551
  : path.call(print, "expr"),
2699
- ]);
2552
+ ];
2700
2553
  case "assignref":
2701
2554
  case "assign": {
2702
2555
  const hasRef = node.kind === "assignref";
@@ -2704,7 +2557,7 @@ function printNode(path, options, print) {
2704
2557
  return printAssignment(
2705
2558
  node.left,
2706
2559
  path.call(print, "left"),
2707
- concat([" ", hasRef ? "=" : node.operator]),
2560
+ [" ", hasRef ? "=" : node.operator],
2708
2561
  node.right,
2709
2562
  path.call(print, "right"),
2710
2563
  hasRef,
@@ -2740,7 +2593,7 @@ function printNode(path, options, print) {
2740
2593
  // $this->lookahead()->type === tt->parenLeft
2741
2594
  // ) {
2742
2595
  if (isInsideParenthesis) {
2743
- return concat(parts);
2596
+ return parts;
2744
2597
  }
2745
2598
 
2746
2599
  // Break between the parens in unaries or in a member expression, i.e.
@@ -2754,9 +2607,7 @@ function printNode(path, options, print) {
2754
2607
  parent.kind === "unary" ||
2755
2608
  (isLookupNode(parent) && parent.kind !== "offsetlookup")
2756
2609
  ) {
2757
- return group(
2758
- concat([indent(concat([softline, concat(parts)])), softline])
2759
- );
2610
+ return group([indent([softline, ...parts]), softline]);
2760
2611
  }
2761
2612
 
2762
2613
  // Avoid indenting sub-expressions in some cases where the first sub-expression is already
@@ -2783,20 +2634,18 @@ function printNode(path, options, print) {
2783
2634
  (shouldInlineLogicalExpression(node) && !samePrecedenceSubExpression) ||
2784
2635
  (!shouldInlineLogicalExpression(node) && shouldIndentIfInlining)
2785
2636
  ) {
2786
- return group(concat(parts));
2637
+ return group(parts);
2787
2638
  }
2788
2639
 
2789
- const rest = concat(parts.slice(1));
2640
+ const rest = parts.slice(1);
2790
2641
 
2791
- return group(
2792
- concat([
2793
- // Don't include the initial expression in the indentation
2794
- // level. The first item is guaranteed to be the first
2795
- // left-most expression.
2796
- parts.length > 0 ? parts[0] : "",
2797
- indent(rest),
2798
- ])
2799
- );
2642
+ return group([
2643
+ // Don't include the initial expression in the indentation
2644
+ // level. The first item is guaranteed to be the first
2645
+ // left-most expression.
2646
+ parts.length > 0 ? parts[0] : "",
2647
+ indent(rest),
2648
+ ]);
2800
2649
  }
2801
2650
  case "retif": {
2802
2651
  const parts = [];
@@ -2816,26 +2665,26 @@ function printNode(path, options, print) {
2816
2665
  node.falseExpr.kind === "bin"
2817
2666
  ? indent(path.call(print, "falseExpr"))
2818
2667
  : path.call(print, "falseExpr");
2819
- const part = concat([
2668
+ const part = [
2820
2669
  node.trueExpr ? line : " ",
2821
2670
  "?",
2822
2671
  node.trueExpr
2823
- ? concat([
2672
+ ? [
2824
2673
  " ",
2825
2674
  node.trueExpr.kind === "bin"
2826
2675
  ? indent(path.call(print, "trueExpr"))
2827
2676
  : path.call(print, "trueExpr"),
2828
2677
  line,
2829
- ])
2678
+ ]
2830
2679
  : "",
2831
2680
  ":",
2832
2681
  node.trueExpr
2833
- ? concat([" ", printedFalseExpr])
2834
- : concat([
2682
+ ? [" ", printedFalseExpr]
2683
+ : [
2835
2684
  shouldInlineRetifFalseExpression(node.falseExpr) ? " " : line,
2836
2685
  printedFalseExpr,
2837
- ]),
2838
- ]);
2686
+ ],
2687
+ ];
2839
2688
 
2840
2689
  parts.push(part);
2841
2690
 
@@ -2861,15 +2710,15 @@ function printNode(path, options, print) {
2861
2710
  const printedTest = path.call(print, "test");
2862
2711
 
2863
2712
  if (!node.trueExpr) {
2864
- const printed = concat([
2713
+ const printed = [
2865
2714
  printedTest,
2866
2715
  pureParent.kind === "bin" ||
2867
2716
  ["print", "echo", "return", "include"].includes(
2868
2717
  firstNonRetifParent.kind
2869
2718
  )
2870
- ? indent(concat(parts))
2871
- : concat(parts),
2872
- ]);
2719
+ ? indent(parts)
2720
+ : parts,
2721
+ ];
2873
2722
 
2874
2723
  // Break between the parens in unaries or in a lookup nodes, i.e.
2875
2724
  //
@@ -2883,19 +2732,17 @@ function printNode(path, options, print) {
2883
2732
  pureParent.kind === "unary" ||
2884
2733
  (isLookupNode(pureParent) && pureParent.kind !== "offsetlookup")
2885
2734
  ) {
2886
- return group(concat([indent(concat([softline, printed])), softline]));
2735
+ return group([indent([softline, printed]), softline]);
2887
2736
  }
2888
2737
 
2889
2738
  return maybeGroup(printed);
2890
2739
  }
2891
2740
 
2892
- return maybeGroup(
2893
- concat([
2894
- node.test.kind === "retif" ? indent(printedTest) : printedTest,
2895
- indent(concat(parts)),
2896
- breakClosingParens ? softline : "",
2897
- ])
2898
- );
2741
+ return maybeGroup([
2742
+ node.test.kind === "retif" ? indent(printedTest) : printedTest,
2743
+ indent(parts),
2744
+ breakClosingParens ? softline : "",
2745
+ ]);
2899
2746
  }
2900
2747
  case "boolean":
2901
2748
  return node.value ? "true" : "false";
@@ -2911,7 +2758,7 @@ function printNode(path, options, print) {
2911
2758
  let linebreak = literalline;
2912
2759
  if (parentParent.type === "heredoc") {
2913
2760
  linebreak = flexible ? hardline : literalline;
2914
- const lines = parentParent.raw.split(/\r?\n/g);
2761
+ const lines = parentParent.raw.split("\n");
2915
2762
  closingTagIndentation = lines[lines.length - 1].search(/\S/);
2916
2763
  if (closingTagIndentation === -1) {
2917
2764
  closingTagIndentation = lines[lines.length - 2].search(/\S/);
@@ -2920,7 +2767,7 @@ function printNode(path, options, print) {
2920
2767
  return join(
2921
2768
  linebreak,
2922
2769
  node.raw
2923
- .split(/\r?\n/g)
2770
+ .split("\n")
2924
2771
  .map((s, i) =>
2925
2772
  i > 0 || node.loc.start.column === 0
2926
2773
  ? s.substring(closingTagIndentation)
@@ -2946,12 +2793,12 @@ function printNode(path, options, print) {
2946
2793
  stringValue = stringValue.substr(0, stringValue.length - 1);
2947
2794
  }
2948
2795
 
2949
- return concat([
2796
+ return [
2950
2797
  node.raw[0] === "b" ? "b" : "",
2951
2798
  quote,
2952
- join(literalline, stringValue.split(/\r?\n/g)),
2799
+ join(literalline, stringValue.split("\n")),
2953
2800
  quote,
2954
- ]);
2801
+ ];
2955
2802
  }
2956
2803
  case "intersectiontype": {
2957
2804
  return printComposedTypes(path, print, "&");
@@ -2962,14 +2809,14 @@ function printNode(path, options, print) {
2962
2809
  case "encapsedpart": {
2963
2810
  const open =
2964
2811
  (node.syntax === "simple" && node.curly) || node.syntax === "complex"
2965
- ? concat([node.curly ? "$" : "", "{"])
2812
+ ? [node.curly ? "$" : "", "{"]
2966
2813
  : "";
2967
2814
  const close =
2968
2815
  (node.syntax === "simple" && node.curly) || node.syntax === "complex"
2969
2816
  ? "}"
2970
2817
  : "";
2971
2818
 
2972
- return concat([open, path.call(print, "expression"), close]);
2819
+ return [open, path.call(print, "expression"), close];
2973
2820
  }
2974
2821
  case "encapsed":
2975
2822
  switch (node.type) {
@@ -2978,16 +2825,16 @@ function printNode(path, options, print) {
2978
2825
  case "heredoc": {
2979
2826
  const flexible = isMinVersion(options.phpVersion, "7.3");
2980
2827
  const linebreak = flexible ? hardline : literalline;
2981
- return concat([
2828
+ return [
2982
2829
  getEncapsedQuotes(node),
2983
2830
  // Respect `indent` for `heredoc` nodes
2984
2831
  node.type === "heredoc" ? linebreak : "",
2985
- concat(path.map(print, "value")),
2832
+ ...path.map(print, "value"),
2986
2833
  getEncapsedQuotes(node, { opening: false }),
2987
2834
  node.type === "heredoc" && docShouldHaveTrailingNewline(path)
2988
2835
  ? hardline
2989
2836
  : "",
2990
- ]);
2837
+ ];
2991
2838
  }
2992
2839
  // istanbul ignore next
2993
2840
  default:
@@ -2996,26 +2843,26 @@ function printNode(path, options, print) {
2996
2843
  case "inline":
2997
2844
  return join(
2998
2845
  literalline,
2999
- node.raw.replace("___PSEUDO_INLINE_PLACEHOLDER___", "").split(/\r?\n/g)
2846
+ node.raw.replace("___PSEUDO_INLINE_PLACEHOLDER___", "").split("\n")
3000
2847
  );
3001
2848
  case "magic":
3002
2849
  return node.value;
3003
2850
  case "nowdoc": {
3004
2851
  const flexible = isMinVersion(options.phpVersion, "7.3");
3005
2852
  const linebreak = flexible ? hardline : literalline;
3006
- return concat([
2853
+ return [
3007
2854
  "<<<'",
3008
2855
  node.label,
3009
2856
  "'",
3010
2857
  linebreak,
3011
- join(linebreak, node.value.split(/\r?\n/g)),
2858
+ join(linebreak, node.value.split("\n")),
3012
2859
  linebreak,
3013
2860
  node.label,
3014
2861
  docShouldHaveTrailingNewline(path) ? hardline : "",
3015
- ]);
2862
+ ];
3016
2863
  }
3017
2864
  case "name":
3018
- return concat([node.resolution === "rn" ? "namespace\\" : "", node.name]);
2865
+ return [node.resolution === "rn" ? "namespace\\" : "", node.name];
3019
2866
  case "literal":
3020
2867
  return path.call(print, "value");
3021
2868
  case "parentreference":
@@ -3042,50 +2889,27 @@ function printNode(path, options, print) {
3042
2889
  const conds =
3043
2890
  armPath.getValue().conds === null
3044
2891
  ? "default"
3045
- : concat(
3046
- armPath.map(
3047
- (condPath, condIdx) =>
3048
- concat(
3049
- [",", line, print(condPath)].slice(condIdx === 0 ? 2 : 0)
3050
- ),
3051
- "conds"
3052
- )
2892
+ : armPath.map(
2893
+ (condPath, condIdx) =>
2894
+ [",", line, print(condPath)].slice(condIdx === 0 ? 2 : 0),
2895
+ "conds"
3053
2896
  );
3054
2897
  const body = armPath.call(print, "body");
3055
- return concat(
3056
- [
3057
- ",",
3058
- hardline,
3059
- group(
3060
- concat([
3061
- group(concat([conds, indent(line)])),
3062
- concat(["=> ", body]),
3063
- ])
3064
- ),
3065
- ].slice(armIdx > 0 ? 0 : 1)
3066
- );
2898
+ return [
2899
+ ",",
2900
+ hardline,
2901
+ group([group([conds, indent(line)]), "=> ", body]),
2902
+ ].slice(armIdx > 0 ? 0 : 1);
3067
2903
  }, "arms");
3068
- return group(
3069
- concat([
3070
- "match (",
3071
- group(
3072
- concat([
3073
- softline,
3074
- indent(concat([path.call(print, "cond")])),
3075
- softline,
3076
- ])
3077
- ),
3078
- ") {",
3079
- group(
3080
- indent(
3081
- concat([...arms, options.trailingCommaPHP ? ifBreak(",") : ""])
3082
- )
3083
- ),
3084
- " ",
3085
- softline,
3086
- "}",
3087
- ])
3088
- );
2904
+ return group([
2905
+ "match (",
2906
+ group([softline, indent(path.call(print, "cond")), softline]),
2907
+ ") {",
2908
+ group(indent([...arms, options.trailingCommaPHP ? ifBreak(",") : ""])),
2909
+ " ",
2910
+ softline,
2911
+ "}",
2912
+ ]);
3089
2913
  }
3090
2914
 
3091
2915
  case "noop":
@@ -3093,27 +2917,25 @@ function printNode(path, options, print) {
3093
2917
  ? comments.printComments(path.getValue().comments, options)
3094
2918
  : "";
3095
2919
  case "namedargument":
3096
- return concat([node.name, ": ", path.call(print, "value")]);
2920
+ return [node.name, ": ", path.call(print, "value")];
3097
2921
 
3098
2922
  case "enumcase":
3099
- return group(
3100
- concat([
3101
- "case ",
3102
- path.call(print, "name"),
3103
- node.value
3104
- ? concat([
3105
- " =",
3106
- printAssignmentRight(
3107
- node.name,
3108
- node.value,
3109
- path.call(print, "value"),
3110
- false,
3111
- options
3112
- ),
3113
- ])
3114
- : "",
3115
- ])
3116
- );
2923
+ return group([
2924
+ "case ",
2925
+ path.call(print, "name"),
2926
+ node.value
2927
+ ? [
2928
+ " =",
2929
+ printAssignmentRight(
2930
+ node.name,
2931
+ node.value,
2932
+ path.call(print, "value"),
2933
+ false,
2934
+ options
2935
+ ),
2936
+ ]
2937
+ : "",
2938
+ ]);
3117
2939
  case "variadicplaceholder":
3118
2940
  return "...";
3119
2941