@prettier/plugin-php 0.20.0 → 0.21.0

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
@@ -1,39 +1,25 @@
1
- "use strict";
2
-
3
- const {
4
- breakParent,
5
- join,
6
- line,
7
- lineSuffix,
8
- group,
9
- conditionalGroup,
10
- indent,
11
- dedent,
12
- ifBreak,
13
- hardline,
14
- softline,
15
- literalline,
16
- align,
17
- dedentToRoot,
18
- } = require("prettier").doc.builders;
19
- const { willBreak } = require("prettier").doc.utils;
20
- const { isNextLineEmptyAfterIndex, hasNewline, hasNewlineInRange } =
21
- require("prettier").util;
22
- const comments = require("./comments");
23
- const pathNeedsParens = require("./needs-parens");
24
-
25
- const {
1
+ import { util as prettierUtil, doc } from "prettier";
2
+ import {
3
+ printAllComments,
4
+ hasTrailingComment,
5
+ hasLeadingComment,
6
+ printDanglingComments,
7
+ printComments,
8
+ isBlockComment,
9
+ hasLeadingOwnLineComment,
10
+ } from "./comments.js";
11
+ import pathNeedsParens from "./needs-parens.js";
12
+ import { locStart, locEnd } from "./loc.js";
13
+
14
+ import {
26
15
  getLast,
27
16
  getPenultimate,
28
- isLastStatement,
29
17
  lineShouldEndWithSemicolon,
30
18
  printNumber,
31
19
  shouldFlatten,
32
20
  maybeStripLeadingSlashFromUse,
33
21
  fileShouldEndWithHardline,
34
22
  hasDanglingComments,
35
- hasLeadingComment,
36
- hasTrailingComment,
37
23
  docShouldHaveTrailingNewline,
38
24
  isLookupNode,
39
25
  isFirstChildrenInlineNode,
@@ -49,12 +35,34 @@ const {
49
35
  isDocNode,
50
36
  getAncestorNode,
51
37
  isReferenceLikeNode,
52
- getNextNode,
53
38
  normalizeMagicMethodName,
39
+ } from "./util.js";
40
+
41
+ const {
42
+ breakParent,
43
+ join,
44
+ line,
45
+ lineSuffix,
46
+ group,
47
+ conditionalGroup,
48
+ indent,
49
+ dedent,
50
+ ifBreak,
51
+ hardline,
52
+ softline,
53
+ literalline,
54
+ align,
55
+ dedentToRoot,
56
+ } = doc.builders;
57
+ const { willBreak } = doc.utils;
58
+ const {
59
+ isNextLineEmptyAfterIndex,
60
+ hasNewline,
61
+ hasNewlineInRange,
54
62
  getNextNonSpaceNonCommentCharacterIndex,
55
63
  isNextLineEmpty,
56
64
  isPreviousLineEmpty,
57
- } = require("./util");
65
+ } = prettierUtil;
58
66
 
59
67
  function isMinVersion(actualVersion, requiredVersion) {
60
68
  return parseFloat(actualVersion) >= parseFloat(requiredVersion);
@@ -80,11 +88,9 @@ function shouldPrintHardlineForOpenBrace(options) {
80
88
  }
81
89
 
82
90
  function genericPrint(path, options, print) {
83
- const node = path.getValue();
91
+ const { node } = path;
84
92
 
85
- if (!node) {
86
- return "";
87
- } else if (typeof node === "string") {
93
+ if (typeof node === "string") {
88
94
  return node;
89
95
  }
90
96
 
@@ -123,14 +129,14 @@ function printNullsafePropertyLookup(path, options, print) {
123
129
  }
124
130
 
125
131
  function printStaticLookup(path, options, print) {
126
- const node = path.getValue();
132
+ const { node } = path;
127
133
  const needCurly = !["variable", "identifier"].includes(node.offset.kind);
128
134
 
129
135
  return ["::", needCurly ? "{" : "", print("offset"), needCurly ? "}" : ""];
130
136
  }
131
137
 
132
138
  function printOffsetLookup(path, options, print) {
133
- const node = path.getValue();
139
+ const { node } = path;
134
140
  const shouldInline =
135
141
  (node.offset && node.offset.kind === "number") ||
136
142
  getAncestorNode(path, "encapsed");
@@ -193,8 +199,7 @@ function printMemberChain(path, options, print) {
193
199
  const { originalText } = options;
194
200
  const nextCharIndex = getNextNonSpaceNonCommentCharacterIndex(
195
201
  originalText,
196
- node,
197
- options
202
+ locEnd(node)
198
203
  );
199
204
  const nextChar = originalText.charAt(nextCharIndex);
200
205
 
@@ -208,11 +213,11 @@ function printMemberChain(path, options, print) {
208
213
  );
209
214
  }
210
215
 
211
- return isNextLineEmpty(originalText, node, options);
216
+ return isNextLineEmpty(originalText, locEnd(node));
212
217
  }
213
218
 
214
219
  function traverse(path) {
215
- const node = path.getValue();
220
+ const { node } = path;
216
221
 
217
222
  if (
218
223
  node.kind === "call" &&
@@ -221,7 +226,7 @@ function printMemberChain(path, options, print) {
221
226
  printedNodes.unshift({
222
227
  node,
223
228
  printed: [
224
- comments.printAllComments(
229
+ printAllComments(
225
230
  path,
226
231
  () => printArgumentsList(path, options, print),
227
232
  options
@@ -247,11 +252,7 @@ function printMemberChain(path, options, print) {
247
252
  printedNodes.unshift({
248
253
  node,
249
254
  needsParens: pathNeedsParens(path, options),
250
- printed: comments.printAllComments(
251
- path,
252
- () => printedMemberish,
253
- options
254
- ),
255
+ printed: printAllComments(path, () => printedMemberish, options),
255
256
  });
256
257
  path.call((what) => traverse(what), "what");
257
258
  } else {
@@ -262,7 +263,7 @@ function printMemberChain(path, options, print) {
262
263
  }
263
264
  }
264
265
 
265
- const node = path.getValue();
266
+ const { node } = path;
266
267
 
267
268
  printedNodes.unshift({
268
269
  node,
@@ -365,7 +366,7 @@ function printMemberChain(path, options, print) {
365
366
 
366
367
  if (
367
368
  printedNodes[i].node.comments &&
368
- comments.hasTrailingComment(printedNodes[i].node)
369
+ hasTrailingComment(printedNodes[i].node)
369
370
  ) {
370
371
  groups.push(currentGroup);
371
372
  currentGroup = [];
@@ -426,8 +427,7 @@ function printMemberChain(path, options, print) {
426
427
  );
427
428
  }
428
429
 
429
- const isExpressionStatement =
430
- path.getParentNode().kind === "expressionstatement";
430
+ const isExpressionStatement = path.parent.kind === "expressionstatement";
431
431
  const shouldMerge =
432
432
  groups.length >= 2 && !groups[1][0].node.comments && shouldNotWrap(groups);
433
433
 
@@ -479,13 +479,9 @@ function printMemberChain(path, options, print) {
479
479
  const flatGroups = groups.slice(0, cutoff).flat();
480
480
 
481
481
  const hasComment =
482
- flatGroups
483
- .slice(1, -1)
484
- .some((node) => comments.hasLeadingComment(node.node)) ||
485
- flatGroups
486
- .slice(0, -1)
487
- .some((node) => comments.hasTrailingComment(node.node)) ||
488
- (groups[cutoff] && comments.hasLeadingComment(groups[cutoff][0].node));
482
+ flatGroups.slice(1, -1).some((node) => hasLeadingComment(node.node)) ||
483
+ flatGroups.slice(0, -1).some((node) => hasTrailingComment(node.node)) ||
484
+ (groups[cutoff] && hasLeadingComment(groups[cutoff][0].node));
489
485
 
490
486
  const hasEncapsedAncestor = getAncestorNode(path, "encapsed");
491
487
 
@@ -579,12 +575,12 @@ function shouldGroupFirstArg(args) {
579
575
  }
580
576
 
581
577
  function printArgumentsList(path, options, print, argumentsKey = "arguments") {
582
- const args = path.getValue()[argumentsKey];
578
+ const args = path.node[argumentsKey];
583
579
 
584
580
  if (args.length === 0) {
585
581
  return [
586
582
  "(",
587
- comments.printDanglingComments(path, options, /* sameIndent */ true),
583
+ printDanglingComments(path, options, /* sameIndent */ true),
588
584
  ")",
589
585
  ];
590
586
  }
@@ -592,15 +588,13 @@ function printArgumentsList(path, options, print, argumentsKey = "arguments") {
592
588
  let anyArgEmptyLine = false;
593
589
  let hasEmptyLineFollowingFirstArg = false;
594
590
 
595
- const lastArgIndex = args.length - 1;
596
- const printedArguments = path.map((argPath, index) => {
597
- const arg = argPath.getNode();
598
- const parts = [print(argPath)];
591
+ const printedArguments = path.map(({ node: arg, isLast, isFirst }) => {
592
+ const parts = [print()];
599
593
 
600
- if (index === lastArgIndex) {
594
+ if (isLast) {
601
595
  // do nothing
602
- } else if (isNextLineEmpty(options.originalText, arg, options)) {
603
- if (index === 0) {
596
+ } else if (isNextLineEmpty(options.originalText, locEnd(arg))) {
597
+ if (isFirst) {
604
598
  hasEmptyLineFollowingFirstArg = true;
605
599
  }
606
600
 
@@ -613,7 +607,7 @@ function printArgumentsList(path, options, print, argumentsKey = "arguments") {
613
607
  return parts;
614
608
  }, argumentsKey);
615
609
 
616
- const node = path.getValue();
610
+ const { node } = path;
617
611
  const lastArg = getLast(args);
618
612
 
619
613
  const maybeTrailingComma =
@@ -649,12 +643,11 @@ function printArgumentsList(path, options, print, argumentsKey = "arguments") {
649
643
 
650
644
  // We want to print the last argument with a special flag
651
645
  let printedExpanded;
652
- let i = 0;
653
646
 
654
- path.each((argPath) => {
655
- if (shouldGroupFirst && i === 0) {
647
+ path.each(({ isLast, isFirst }) => {
648
+ if (shouldGroupFirst && isFirst) {
656
649
  printedExpanded = [
657
- argPath.call(() => print([], { expandFirstArg: true })),
650
+ print([], { expandFirstArg: true }),
658
651
  printedArguments.length > 1 ? "," : "",
659
652
  hasEmptyLineFollowingFirstArg ? hardline : line,
660
653
  hasEmptyLineFollowingFirstArg ? hardline : "",
@@ -662,14 +655,12 @@ function printArgumentsList(path, options, print, argumentsKey = "arguments") {
662
655
  ];
663
656
  }
664
657
 
665
- if (shouldGroupLast && i === args.length - 1) {
658
+ if (shouldGroupLast && isLast) {
666
659
  printedExpanded = [
667
660
  ...printedArguments.slice(0, -1),
668
- argPath.call(() => print([], { expandLastArg: true })),
661
+ print([], { expandLastArg: true }),
669
662
  ];
670
663
  }
671
-
672
- i++;
673
664
  }, argumentsKey);
674
665
 
675
666
  const somePrintedArgumentsWillBreak = printedArguments.some(willBreak);
@@ -751,7 +742,7 @@ function printBinaryExpression(
751
742
  isInsideParenthesis
752
743
  ) {
753
744
  let parts = [];
754
- const node = path.getValue();
745
+ const { node } = path;
755
746
 
756
747
  if (node.kind === "bin") {
757
748
  // Put all operators with the same precedence level in the same
@@ -790,7 +781,7 @@ function printBinaryExpression(
790
781
 
791
782
  // If there's only a single binary expression, we want to create a group
792
783
  // in order to avoid having a small right part like -1 be on its own line.
793
- const parent = path.getParentNode();
784
+ const { parent } = path;
794
785
  const shouldGroup =
795
786
  !(isInsideParenthesis && ["||", "&&"].includes(node.type)) &&
796
787
  getNodeKindIncludingLogical(parent) !==
@@ -813,7 +804,7 @@ function printBinaryExpression(
813
804
  // the other ones since we don't call the normal print on bin,
814
805
  // only for the left and right parts
815
806
  if (isNested && node.comments) {
816
- parts = comments.printAllComments(path, () => parts, options);
807
+ parts = printAllComments(path, () => parts, options);
817
808
  }
818
809
  } else {
819
810
  // Our stopping case. Simply print the node normally.
@@ -824,7 +815,7 @@ function printBinaryExpression(
824
815
  }
825
816
 
826
817
  function printLookupNodes(path, options, print) {
827
- const node = path.getValue();
818
+ const { node } = path;
828
819
 
829
820
  switch (node.kind) {
830
821
  case "propertylookup":
@@ -835,9 +826,9 @@ function printLookupNodes(path, options, print) {
835
826
  return printStaticLookup(path, options, print);
836
827
  case "offsetlookup":
837
828
  return printOffsetLookup(path, options, print);
838
- /* istanbul ignore next */
829
+ /* c8 ignore next 2 */
839
830
  default:
840
- return `Have not implemented lookup kind ${node.kind} yet.`;
831
+ throw new Error(`Have not implemented lookup kind ${node.kind} yet.`);
841
832
  }
842
833
  }
843
834
 
@@ -855,24 +846,21 @@ function getEncapsedQuotes(node, { opening = true } = {}) {
855
846
  return quotes[node.type];
856
847
  }
857
848
 
858
- /* istanbul ignore next */
859
- return `Unimplemented encapsed type ${node.type}`;
849
+ /* c8 ignore next */
850
+ throw new Error(`Unimplemented encapsed type ${node.type}`);
860
851
  }
861
852
 
862
853
  function printArrayItems(path, options, print) {
863
854
  const printedElements = [];
864
855
  let separatorParts = [];
865
856
 
866
- path.each((childPath) => {
857
+ path.each(({ node }) => {
867
858
  printedElements.push(separatorParts);
868
- printedElements.push(group(print(childPath)));
859
+ printedElements.push(group(print()));
869
860
 
870
861
  separatorParts = [",", line];
871
862
 
872
- if (
873
- childPath.getValue() &&
874
- isNextLineEmpty(options.originalText, childPath.getValue(), options)
875
- ) {
863
+ if (node && isNextLineEmpty(options.originalText, locEnd(node))) {
876
864
  separatorParts.push(softline);
877
865
  }
878
866
  }, "items");
@@ -925,22 +913,26 @@ function wrapPartsIntoGroups(parts, indexes) {
925
913
  }
926
914
 
927
915
  function printLines(path, options, print, childrenAttribute = "children") {
928
- const node = path.getValue();
929
- const parentNode = path.getParentNode();
916
+ const { node, parent: parentNode } = path;
930
917
 
931
918
  let lastInlineIndex = -1;
932
919
 
933
920
  const parts = [];
934
921
  const groupIndexes = [];
935
922
 
936
- path.map((childPath, index) => {
937
- const childNode = childPath.getValue();
923
+ path.map(() => {
924
+ const {
925
+ node: childNode,
926
+ next: nextNode,
927
+ isFirst: isFirstNode,
928
+ isLast: isLastNode,
929
+ index,
930
+ } = path;
931
+
938
932
  const isInlineNode = childNode.kind === "inline";
939
- const printedPath = print(childPath);
940
- const children = node[childrenAttribute];
941
- const nextNode = children[index + 1];
933
+ const printedPath = print();
942
934
  const canPrintBlankLine =
943
- !isLastStatement(childPath) &&
935
+ !isLastNode &&
944
936
  !isInlineNode &&
945
937
  (nextNode && nextNode.kind === "case"
946
938
  ? !isFirstChildrenInlineNode(path)
@@ -950,13 +942,11 @@ function printLines(path, options, print, childrenAttribute = "children") {
950
942
  printedPath,
951
943
  canPrintBlankLine ? hardline : "",
952
944
  canPrintBlankLine &&
953
- isNextLineEmpty(options.originalText, childNode, options)
945
+ isNextLineEmpty(options.originalText, locEnd(childNode))
954
946
  ? hardline
955
947
  : "",
956
948
  ];
957
949
 
958
- const isFirstNode = index === 0;
959
- const isLastNode = children.length - 1 === index;
960
950
  const isBlockNestedNode =
961
951
  node.kind === "block" &&
962
952
  parentNode &&
@@ -981,7 +971,7 @@ function printLines(path, options, print, childrenAttribute = "children") {
981
971
  (isInlineNode ? prevLastInlineIndex : lastInlineIndex) + 1;
982
972
  const end = isLastNode && !isInlineNode ? index + 1 : index;
983
973
  const prevInlineNode =
984
- children[isInlineNode ? prevLastInlineIndex : lastInlineIndex];
974
+ path.siblings[isInlineNode ? prevLastInlineIndex : lastInlineIndex];
985
975
  const alignment = prevInlineNode
986
976
  ? getAlignment(prevInlineNode.raw)
987
977
  : "";
@@ -1019,7 +1009,7 @@ function printLines(path, options, print, childrenAttribute = "children") {
1019
1009
  ? "<?php"
1020
1010
  : "",
1021
1011
  node.kind === "namespace" || !isBlockNestedNode ? hardline : "",
1022
- comments.printComments(childNode.leadingComments, options),
1012
+ printComments(childNode.leadingComments, options),
1023
1013
  hardline,
1024
1014
  "?>",
1025
1015
  ]
@@ -1027,6 +1017,7 @@ function printLines(path, options, print, childrenAttribute = "children") {
1027
1017
  ? ""
1028
1018
  : [beforeCloseTagInlineNode, "?>"];
1029
1019
 
1020
+ //FIXME getNode is used to get ancestors, but it seems this means to get next sibling?
1030
1021
  const nextV = path.getNode(index + 1);
1031
1022
  const skipLastComment = nextV && nextV.children && nextV.children.length;
1032
1023
 
@@ -1035,9 +1026,7 @@ function printLines(path, options, print, childrenAttribute = "children") {
1035
1026
  ? [
1036
1027
  openTag,
1037
1028
  hardline,
1038
- skipLastComment
1039
- ? comments.printComments(childNode.comments, options)
1040
- : "",
1029
+ skipLastComment ? printComments(childNode.comments, options) : "",
1041
1030
  hardline,
1042
1031
  ]
1043
1032
  : isProgramLikeNode(node) && isLastNode
@@ -1064,7 +1053,7 @@ function printLines(path, options, print, childrenAttribute = "children") {
1064
1053
  between && between[2] && between[2].includes("\n")
1065
1054
  ? [hardline, between[2].split("\n").length > 2 ? hardline : ""]
1066
1055
  : " ",
1067
- node.comments ? comments.printComments(node.comments, options) : "",
1056
+ node.comments ? printComments(node.comments, options) : "",
1068
1057
  ];
1069
1058
 
1070
1059
  const shortEcho =
@@ -1082,8 +1071,8 @@ function printLines(path, options, print, childrenAttribute = "children") {
1082
1071
  ? [
1083
1072
  hasNewlineInRange(
1084
1073
  options.originalText.trimEnd(),
1085
- options.locEnd(lastNode),
1086
- options.locEnd(node)
1074
+ locEnd(lastNode),
1075
+ locEnd(node)
1087
1076
  )
1088
1077
  ? !(
1089
1078
  lastNode.kind === "inline" &&
@@ -1093,7 +1082,7 @@ function printLines(path, options, print, childrenAttribute = "children") {
1093
1082
  ? hardline
1094
1083
  : ""
1095
1084
  : " ",
1096
- isNextLineEmpty(options.originalText, lastNode, options)
1085
+ isNextLineEmpty(options.originalText, locEnd(lastNode))
1097
1086
  ? hardline
1098
1087
  : "",
1099
1088
  ]
@@ -1111,17 +1100,15 @@ function printLines(path, options, print, childrenAttribute = "children") {
1111
1100
  }
1112
1101
 
1113
1102
  function printStatements(path, options, print, childrenAttribute) {
1114
- return path.map((childPath) => {
1103
+ return path.map(({ node, isLast }) => {
1115
1104
  const parts = [];
1116
1105
 
1117
- parts.push(print(childPath));
1106
+ parts.push(print());
1118
1107
 
1119
- if (!isLastStatement(childPath)) {
1108
+ if (!isLast) {
1120
1109
  parts.push(hardline);
1121
1110
 
1122
- if (
1123
- isNextLineEmpty(options.originalText, childPath.getValue(), options)
1124
- ) {
1111
+ if (isNextLineEmpty(options.originalText, locEnd(node))) {
1125
1112
  parts.push(hardline);
1126
1113
  }
1127
1114
  }
@@ -1138,28 +1125,25 @@ function printClassPart(
1138
1125
  beforePart = " ",
1139
1126
  afterPart = " "
1140
1127
  ) {
1141
- const node = path.getValue();
1142
- const printedBeforePart = hasDanglingComments(node[part])
1128
+ const value = path.node[part];
1129
+ const printedBeforePart = hasDanglingComments(value)
1143
1130
  ? [
1144
1131
  hardline,
1145
- path.call(
1146
- () => comments.printDanglingComments(path, options, true),
1147
- part
1148
- ),
1132
+ path.call(() => printDanglingComments(path, options, true), part),
1149
1133
  hardline,
1150
1134
  ]
1151
1135
  : beforePart;
1152
- const printedPartItems = Array.isArray(node[part])
1136
+ const printedPartItems = Array.isArray(value)
1153
1137
  ? group(
1154
1138
  join(
1155
1139
  ",",
1156
- path.map((itemPartPath) => {
1157
- const printedPart = print(itemPartPath);
1140
+ path.map(({ node }) => {
1141
+ const printedPart = print();
1158
1142
  // Check if any of the implements nodes have comments
1159
- return hasDanglingComments(itemPartPath.getValue())
1143
+ return hasDanglingComments(node)
1160
1144
  ? [
1161
1145
  hardline,
1162
- comments.printDanglingComments(itemPartPath, options, true),
1146
+ printDanglingComments(path, options, true),
1163
1147
  hardline,
1164
1148
  printedPart,
1165
1149
  ]
@@ -1178,23 +1162,23 @@ function printClassPart(
1178
1162
 
1179
1163
  function printAttrs(path, options, print, { inline = false } = {}) {
1180
1164
  const allAttrs = [];
1181
- if (!path.getValue().attrGroups) {
1165
+ if (!path.node.attrGroups) {
1182
1166
  return [];
1183
1167
  }
1184
- path.each((agPath) => {
1168
+ path.each(() => {
1185
1169
  const attrGroup = ["#["];
1186
1170
  if (!inline && allAttrs.length > 0) {
1187
1171
  allAttrs.push(hardline);
1188
1172
  }
1189
1173
  attrGroup.push(softline);
1190
- agPath.each((attrPath) => {
1191
- const attrNode = attrPath.getValue();
1174
+ path.each(() => {
1175
+ const attrNode = path.node;
1192
1176
  if (attrGroup.length > 2) {
1193
1177
  attrGroup.push(",", line);
1194
1178
  }
1195
1179
  const attrStmt = [attrNode.name];
1196
1180
  if (attrNode.args.length > 0) {
1197
- attrStmt.push(printArgumentsList(attrPath, options, print, "args"));
1181
+ attrStmt.push(printArgumentsList(path, options, print, "args"));
1198
1182
  }
1199
1183
  attrGroup.push(group(attrStmt));
1200
1184
  }, "attrs");
@@ -1215,7 +1199,7 @@ function printAttrs(path, options, print, { inline = false } = {}) {
1215
1199
  }
1216
1200
 
1217
1201
  function printClass(path, options, print) {
1218
- const node = path.getValue();
1202
+ const { node } = path;
1219
1203
  const isAnonymousClass = node.kind === "class" && node.isAnonymous;
1220
1204
  const attrs = printAttrs(path, options, print, { inline: isAnonymousClass });
1221
1205
  const declaration = isAnonymousClass ? [] : [...attrs];
@@ -1326,7 +1310,7 @@ function printClass(path, options, print) {
1326
1310
  hasEmptyClassBody ? "" : hardline,
1327
1311
  printStatements(path, options, print, "body"),
1328
1312
  ]),
1329
- comments.printDanglingComments(path, options, true),
1313
+ printDanglingComments(path, options, true),
1330
1314
  isAnonymousClass && hasEmptyClassBody ? softline : hardline,
1331
1315
  "}",
1332
1316
  ];
@@ -1335,7 +1319,7 @@ function printClass(path, options, print) {
1335
1319
  }
1336
1320
 
1337
1321
  function printFunction(path, options, print) {
1338
- const node = path.getValue();
1322
+ const { node } = path;
1339
1323
  const declAttrs = printAttrs(path, options, print, {
1340
1324
  inline: node.kind === "closure",
1341
1325
  });
@@ -1380,10 +1364,7 @@ function printFunction(path, options, print) {
1380
1364
  ": ",
1381
1365
  hasDanglingComments(node.type)
1382
1366
  ? [
1383
- path.call(
1384
- () => comments.printDanglingComments(path, options, true),
1385
- "type"
1386
- ),
1367
+ path.call(() => printDanglingComments(path, options, true), "type"),
1387
1368
  " ",
1388
1369
  ]
1389
1370
  : "",
@@ -1444,7 +1425,7 @@ function printBodyControlStructure(
1444
1425
  print,
1445
1426
  bodyProperty = "body"
1446
1427
  ) {
1447
- const node = path.getValue();
1428
+ const { node } = path;
1448
1429
 
1449
1430
  if (!node[bodyProperty]) {
1450
1431
  return ";";
@@ -1523,9 +1504,7 @@ function printAssignmentRight(
1523
1504
  ) {
1524
1505
  const ref = hasRef ? "&" : "";
1525
1506
 
1526
- if (
1527
- comments.hasLeadingOwnLineComment(options.originalText, rightNode, options)
1528
- ) {
1507
+ if (hasLeadingOwnLineComment(options.originalText, rightNode)) {
1529
1508
  return indent([hardline, ref, printedRight]);
1530
1509
  }
1531
1510
 
@@ -1561,37 +1540,37 @@ function needsHardlineAfterDanglingComment(node) {
1561
1540
  node.comments.filter((comment) => !comment.leading && !comment.trailing)
1562
1541
  );
1563
1542
 
1564
- return lastDanglingComment && !comments.isBlockComment(lastDanglingComment);
1543
+ return lastDanglingComment && !isBlockComment(lastDanglingComment);
1565
1544
  }
1566
1545
 
1567
1546
  function stringHasNewLines(node) {
1568
1547
  return node.raw.includes("\n");
1569
1548
  }
1570
1549
 
1571
- function isStringOnItsOwnLine(node, text, options) {
1550
+ function isStringOnItsOwnLine(node, text) {
1572
1551
  return (
1573
1552
  (node.kind === "string" ||
1574
1553
  (node.kind === "encapsed" &&
1575
1554
  (node.type === "string" || node.type === "shell"))) &&
1576
1555
  stringHasNewLines(node) &&
1577
- !hasNewline(text, options.locStart(node), { backwards: true })
1556
+ !hasNewline(text, locStart(node), { backwards: true })
1578
1557
  );
1579
1558
  }
1580
1559
 
1581
1560
  function printComposedTypes(path, print, glue) {
1582
1561
  return group(
1583
- path.map((uPath, i) => (i === 0 ? [print()] : [glue, print()]), "types")
1562
+ path.map(({ isFirst }) => (isFirst ? [print()] : [glue, print()]), "types")
1584
1563
  );
1585
1564
  }
1586
1565
 
1587
1566
  function printNode(path, options, print) {
1588
- const node = path.getValue();
1567
+ const { node } = path;
1589
1568
 
1590
1569
  switch (node.kind) {
1591
1570
  case "program": {
1592
1571
  return group([
1593
1572
  printLines(path, options, print),
1594
- comments.printDanglingComments(
1573
+ printDanglingComments(
1595
1574
  path,
1596
1575
  options,
1597
1576
  /* sameIndent */ true,
@@ -1604,14 +1583,11 @@ function printNode(path, options, print) {
1604
1583
  case "block":
1605
1584
  return [
1606
1585
  printLines(path, options, print),
1607
- comments.printDanglingComments(path, options, true),
1586
+ printDanglingComments(path, options, true),
1608
1587
  ];
1609
1588
  case "declare": {
1610
1589
  const printDeclareArguments = (path) => {
1611
- return join(
1612
- ", ",
1613
- path.map((directive) => print(directive), "directives")
1614
- );
1590
+ return join(", ", path.map(print, "directives"));
1615
1591
  };
1616
1592
 
1617
1593
  if (["block", "short"].includes(node.mode)) {
@@ -1623,19 +1599,17 @@ function printNode(path, options, print) {
1623
1599
  node.children.length > 0
1624
1600
  ? indent([hardline, printLines(path, options, print)])
1625
1601
  : "",
1626
- comments.printDanglingComments(path, options),
1602
+ printDanglingComments(path, options),
1627
1603
  hardline,
1628
1604
  node.mode === "block" ? "}" : "enddeclare;",
1629
1605
  ];
1630
1606
  }
1631
1607
 
1632
- const nextNode = getNextNode(path, node);
1633
-
1634
1608
  return [
1635
1609
  "declare(",
1636
1610
  printDeclareArguments(path),
1637
1611
  ")",
1638
- nextNode && nextNode.kind === "inline" ? "" : ";",
1612
+ path.next?.kind === "inline" ? "" : ";",
1639
1613
  ];
1640
1614
  }
1641
1615
  case "declaredirective":
@@ -1648,7 +1622,7 @@ function printNode(path, options, print) {
1648
1622
  : "",
1649
1623
  node.withBrackets ? "{" : ";",
1650
1624
  hasDanglingComments(node)
1651
- ? [" ", comments.printDanglingComments(path, options, true)]
1625
+ ? [" ", printDanglingComments(path, options, true)]
1652
1626
  : "",
1653
1627
  node.children.length > 0
1654
1628
  ? node.withBrackets
@@ -1658,11 +1632,7 @@ function printNode(path, options, print) {
1658
1632
  ? ""
1659
1633
  : [
1660
1634
  hardline,
1661
- isNextLineEmptyAfterNamespace(
1662
- options.originalText,
1663
- node,
1664
- options.locStart
1665
- )
1635
+ isNextLineEmptyAfterNamespace(options.originalText, node)
1666
1636
  ? hardline
1667
1637
  : "",
1668
1638
  ],
@@ -1679,10 +1649,7 @@ function printNode(path, options, print) {
1679
1649
  node.name
1680
1650
  ? [maybeStripLeadingSlashFromUse(node.name), "\\{", softline]
1681
1651
  : "",
1682
- join(
1683
- [",", line],
1684
- path.map((item) => print(item), "items")
1685
- ),
1652
+ join([",", line], path.map(print, "items")),
1686
1653
  ]),
1687
1654
  node.name
1688
1655
  ? [
@@ -1697,7 +1664,7 @@ function printNode(path, options, print) {
1697
1664
  node.type ? [node.type, " "] : "",
1698
1665
  maybeStripLeadingSlashFromUse(node.name),
1699
1666
  hasDanglingComments(node)
1700
- ? [" ", comments.printDanglingComments(path, options, true)]
1667
+ ? [" ", printDanglingComments(path, options, true)]
1701
1668
  : "",
1702
1669
  node.alias ? [" as ", print("alias")] : "",
1703
1670
  ];
@@ -1740,11 +1707,7 @@ function printNode(path, options, print) {
1740
1707
  hardline,
1741
1708
  ]
1742
1709
  : hasDanglingComments(node)
1743
- ? [
1744
- line,
1745
- comments.printDanglingComments(path, options, true),
1746
- line,
1747
- ]
1710
+ ? [line, printDanglingComments(path, options, true), line]
1748
1711
  : "",
1749
1712
  "}",
1750
1713
  ]
@@ -1794,7 +1757,7 @@ function printNode(path, options, print) {
1794
1757
  // no node to attach comments that fall in between the parameter name
1795
1758
  // and value, we store them as dangling comments
1796
1759
  hasDanglingComments(node) ? " " : "",
1797
- comments.printDanglingComments(path, options, true),
1760
+ printDanglingComments(path, options, true),
1798
1761
  " =",
1799
1762
  printAssignmentRight(
1800
1763
  node.name,
@@ -1831,13 +1794,10 @@ function printNode(path, options, print) {
1831
1794
  ]);
1832
1795
  case "propertystatement": {
1833
1796
  const attrs = [];
1834
- path.map(
1835
- (propPath) => attrs.push(...printAttrs(propPath, options, print)),
1836
- "properties"
1837
- );
1838
- const printed = path.map((childPath) => {
1839
- return print(childPath);
1797
+ path.each(() => {
1798
+ attrs.push(...printAttrs(path, options, print));
1840
1799
  }, "properties");
1800
+ const printed = path.map(print, "properties");
1841
1801
 
1842
1802
  const hasValue = node.properties.some((property) => property.value);
1843
1803
 
@@ -1885,7 +1845,7 @@ function printNode(path, options, print) {
1885
1845
  const commentOnOwnLine =
1886
1846
  (hasTrailingComment(node.body) &&
1887
1847
  node.body.comments.some(
1888
- (comment) => comment.trailing && !comments.isBlockComment(comment)
1848
+ (comment) => comment.trailing && !isBlockComment(comment)
1889
1849
  )) ||
1890
1850
  needsHardlineAfterDanglingComment(node);
1891
1851
  const elseOnSameLine = !commentOnOwnLine;
@@ -1893,10 +1853,10 @@ function printNode(path, options, print) {
1893
1853
 
1894
1854
  if (hasDanglingComments(node)) {
1895
1855
  parts.push(
1896
- isNextLineEmpty(options.originalText, node.body, options)
1856
+ isNextLineEmpty(options.originalText, locEnd(node.body))
1897
1857
  ? hardline
1898
1858
  : "",
1899
- comments.printDanglingComments(path, options, true),
1859
+ printDanglingComments(path, options, true),
1900
1860
  commentOnOwnLine ? hardline : " "
1901
1861
  );
1902
1862
  }
@@ -1938,7 +1898,7 @@ function printNode(path, options, print) {
1938
1898
  // We want to keep dangling comments above the loop to stay consistent.
1939
1899
  // Any comment positioned between the for statement and the parentheses
1940
1900
  // is going to be printed before the statement.
1941
- const dangling = comments.printDanglingComments(
1901
+ const dangling = printDanglingComments(
1942
1902
  path,
1943
1903
  options,
1944
1904
  /* sameLine */ true
@@ -1977,7 +1937,7 @@ function printNode(path, options, print) {
1977
1937
  // We want to keep dangling comments above the loop to stay consistent.
1978
1938
  // Any comment positioned between the for statement and the parentheses
1979
1939
  // is going to be printed before the statement.
1980
- const dangling = comments.printDanglingComments(
1940
+ const dangling = printDanglingComments(
1981
1941
  path,
1982
1942
  options,
1983
1943
  /* sameLine */ true
@@ -2075,7 +2035,7 @@ function printNode(path, options, print) {
2075
2035
  // Multiline strings as single arguments
2076
2036
  if (
2077
2037
  node.arguments.length === 1 &&
2078
- isStringOnItsOwnLine(node.arguments[0], options.originalText, options)
2038
+ isStringOnItsOwnLine(node.arguments[0], options.originalText)
2079
2039
  ) {
2080
2040
  return [
2081
2041
  print("what"),
@@ -2100,7 +2060,7 @@ function printNode(path, options, print) {
2100
2060
  if (
2101
2061
  !isAnonymousClassNode &&
2102
2062
  node.arguments.length === 1 &&
2103
- isStringOnItsOwnLine(node.arguments[0], options.originalText, options)
2063
+ isStringOnItsOwnLine(node.arguments[0], options.originalText)
2104
2064
  ) {
2105
2065
  return [
2106
2066
  "new ",
@@ -2120,7 +2080,7 @@ function printNode(path, options, print) {
2120
2080
  parts.push(
2121
2081
  node.what.leadingComments &&
2122
2082
  node.what.leadingComments[0].kind === "commentblock"
2123
- ? [comments.printComments(node.what.leadingComments, options), " "]
2083
+ ? [printComments(node.what.leadingComments, options), " "]
2124
2084
  : "",
2125
2085
  ...path.call(
2126
2086
  () => printAttrs(path, options, print, { inline: true }),
@@ -2155,11 +2115,11 @@ function printNode(path, options, print) {
2155
2115
  case "nullsafepropertylookup":
2156
2116
  case "staticlookup":
2157
2117
  case "offsetlookup": {
2158
- const parent = path.getParentNode();
2118
+ const { parent } = path;
2159
2119
 
2120
+ // TODO: Use `AstPath.findAncestor` when it's stable
2160
2121
  let firstNonMemberParent;
2161
2122
  let i = 0;
2162
-
2163
2123
  do {
2164
2124
  firstNonMemberParent = path.getParentNode(i);
2165
2125
  i++;
@@ -2192,10 +2152,10 @@ function printNode(path, options, print) {
2192
2152
  node.useDie ? "die" : "exit",
2193
2153
  "(",
2194
2154
  node.expression
2195
- ? isStringOnItsOwnLine(node.expression, options.originalText, options)
2155
+ ? isStringOnItsOwnLine(node.expression, options.originalText)
2196
2156
  ? print("expression")
2197
2157
  : [indent([softline, print("expression")]), softline]
2198
- : comments.printDanglingComments(path, options),
2158
+ : printDanglingComments(path, options),
2199
2159
  ")",
2200
2160
  ]);
2201
2161
  case "global":
@@ -2225,11 +2185,7 @@ function printNode(path, options, print) {
2225
2185
  return [
2226
2186
  hasDanglingComments(node)
2227
2187
  ? [
2228
- comments.printDanglingComments(
2229
- path,
2230
- options,
2231
- /* sameIndent */ true
2232
- ),
2188
+ printDanglingComments(path, options, /* sameIndent */ true),
2233
2189
  hardline,
2234
2190
  ]
2235
2191
  : "",
@@ -2239,15 +2195,13 @@ function printNode(path, options, print) {
2239
2195
  case "eval":
2240
2196
  return group([
2241
2197
  "eval(",
2242
- isStringOnItsOwnLine(node.source, options.originalText, options)
2198
+ isStringOnItsOwnLine(node.source, options.originalText)
2243
2199
  ? print("source")
2244
2200
  : [indent([softline, print("source")]), softline],
2245
2201
  ")",
2246
2202
  ]);
2247
2203
  case "echo": {
2248
- const printedArguments = path.map((childPath) => {
2249
- return print(childPath);
2250
- }, "expressions");
2204
+ const printedArguments = path.map(print, "expressions");
2251
2205
 
2252
2206
  let firstVariable;
2253
2207
 
@@ -2288,7 +2242,7 @@ function printNode(path, options, print) {
2288
2242
  if (hasDanglingComments(node)) {
2289
2243
  parts.push(
2290
2244
  " ",
2291
- comments.printDanglingComments(path, options, /* sameIndent */ true)
2245
+ printDanglingComments(path, options, /* sameIndent */ true)
2292
2246
  );
2293
2247
  }
2294
2248
 
@@ -2308,8 +2262,7 @@ function printNode(path, options, print) {
2308
2262
  ")",
2309
2263
  ]);
2310
2264
  case "variable": {
2311
- const parent = path.getParentNode();
2312
- const parentParent = path.getParentNode(1);
2265
+ const { parent, grandparent: parentParent } = path;
2313
2266
  const ampersand = parent.kind === "assign" ? "" : node.byref ? "&" : "";
2314
2267
  const dollar =
2315
2268
  (parent.kind === "encapsedpart" &&
@@ -2330,7 +2283,7 @@ function printNode(path, options, print) {
2330
2283
  case "constantstatement":
2331
2284
  case "classconstant": {
2332
2285
  const attrs = printAttrs(path, options, print);
2333
- const printed = path.map((childPath) => print(childPath), "constants");
2286
+ const printed = path.map(print, "constants");
2334
2287
 
2335
2288
  let firstVariable;
2336
2289
 
@@ -2361,9 +2314,7 @@ function printNode(path, options, print) {
2361
2314
  options
2362
2315
  );
2363
2316
  case "static": {
2364
- const printed = path.map((childPath) => {
2365
- return print(childPath);
2366
- }, "variables");
2317
+ const printed = path.map(print, "variables");
2367
2318
 
2368
2319
  const hasValue = node.variables.some((item) => item.defaultValue);
2369
2320
 
@@ -2411,7 +2362,7 @@ function printNode(path, options, print) {
2411
2362
 
2412
2363
  return group([
2413
2364
  open,
2414
- comments.printDanglingComments(path, options),
2365
+ printDanglingComments(path, options),
2415
2366
  softline,
2416
2367
  close,
2417
2368
  ]);
@@ -2433,15 +2384,15 @@ function printNode(path, options, print) {
2433
2384
 
2434
2385
  const [firstProperty] = node.items
2435
2386
  .filter((node) => node.kind !== "noop")
2436
- .sort((a, b) => options.locStart(a) - options.locStart(b));
2387
+ .sort((a, b) => locStart(a) - locStart(b));
2437
2388
  const isAssociative = !!(firstProperty && firstProperty.key);
2438
2389
  const shouldBreak =
2439
2390
  isAssociative &&
2440
2391
  firstProperty &&
2441
2392
  hasNewlineInRange(
2442
2393
  options.originalText,
2443
- options.locStart(node),
2444
- options.locStart(firstProperty)
2394
+ locStart(node),
2395
+ locStart(firstProperty)
2445
2396
  );
2446
2397
 
2447
2398
  return group(
@@ -2459,7 +2410,7 @@ function printNode(path, options, print) {
2459
2410
  ]
2460
2411
  : ""
2461
2412
  ),
2462
- comments.printDanglingComments(path, options, true),
2413
+ printDanglingComments(path, options, true),
2463
2414
  softline,
2464
2415
  close,
2465
2416
  ],
@@ -2528,8 +2479,7 @@ function printNode(path, options, print) {
2528
2479
  );
2529
2480
  }
2530
2481
  case "bin": {
2531
- const parent = path.getParentNode();
2532
- const parentParent = path.getParentNode(1);
2482
+ const { parent, grandparent: parentParent } = path;
2533
2483
  const isInsideParenthesis =
2534
2484
  node !== parent.body &&
2535
2485
  (parent.kind === "if" ||
@@ -2612,8 +2562,9 @@ function printNode(path, options, print) {
2612
2562
  }
2613
2563
  case "retif": {
2614
2564
  const parts = [];
2615
- const parent = path.getParentNode();
2565
+ const { parent } = path;
2616
2566
 
2567
+ // TODO: Use `AstPath.findAncestor` when it's stable
2617
2568
  // Find the outermost non-retif parent, and the outermost retif parent.
2618
2569
  let currentParent;
2619
2570
  let i = 0;
@@ -2660,7 +2611,7 @@ function printNode(path, options, print) {
2660
2611
  // ? $b
2661
2612
  // : $c
2662
2613
  // )->call()
2663
- const parentParent = path.getParentNode(1);
2614
+ const parentParent = path.grandparent;
2664
2615
  const pureParent =
2665
2616
  parent.kind === "cast" && parentParent ? parentParent : parent;
2666
2617
  const breakLookupNodes = [
@@ -2712,10 +2663,10 @@ function printNode(path, options, print) {
2712
2663
  case "number":
2713
2664
  return printNumber(node.value);
2714
2665
  case "string": {
2715
- const parent = path.getParentNode();
2666
+ const { parent } = path;
2716
2667
 
2717
2668
  if (parent.kind === "encapsedpart") {
2718
- const parentParent = path.getParentNode(1);
2669
+ const parentParent = path.grandparent;
2719
2670
  let closingTagIndentation = 0;
2720
2671
  const flexible = isMinVersion(options.phpVersion, "7.3");
2721
2672
  let linebreak = literalline;
@@ -2799,9 +2750,9 @@ function printNode(path, options, print) {
2799
2750
  : "",
2800
2751
  ];
2801
2752
  }
2802
- // istanbul ignore next
2753
+ /* c8 ignore next 2 */
2803
2754
  default:
2804
- return `Have not implemented kind ${node.type} yet.`;
2755
+ throw new Error(`Have not implemented kind ${node.type} yet.`);
2805
2756
  }
2806
2757
  case "inline":
2807
2758
  return join(
@@ -2839,7 +2790,7 @@ function printNode(path, options, print) {
2839
2790
  case "nullkeyword":
2840
2791
  return "null";
2841
2792
  case "identifier": {
2842
- const parent = path.getParentNode();
2793
+ const { parent } = path;
2843
2794
 
2844
2795
  if (parent.kind === "method") {
2845
2796
  node.name = normalizeMagicMethodName(node.name);
@@ -2848,19 +2799,18 @@ function printNode(path, options, print) {
2848
2799
  return print("name");
2849
2800
  }
2850
2801
  case "match": {
2851
- const lastArmIndex = node.arms.length - 1;
2852
- const arms = path.map((armPath, armIdx) => {
2853
- const armNode = armPath.getValue();
2802
+ const arms = path.map(() => {
2803
+ const armNode = path.node;
2854
2804
 
2855
- const maybeLeadingComment = comments.hasLeadingComment(armNode)
2856
- ? [comments.printComments(armNode.leadingComments, options), hardline]
2805
+ const maybeLeadingComment = hasLeadingComment(armNode)
2806
+ ? [printComments(armNode.leadingComments, options), hardline]
2857
2807
  : [];
2858
2808
  const maybeTrailingComma =
2859
- armIdx < lastArmIndex || options.trailingCommaPHP ? "," : "";
2860
- const maybeTrailingComment = comments.hasTrailingComment(armNode)
2809
+ !path.isLast || options.trailingCommaPHP ? "," : "";
2810
+ const maybeTrailingComment = hasTrailingComment(armNode)
2861
2811
  ? [
2862
2812
  " ",
2863
- comments.printComments(
2813
+ printComments(
2864
2814
  armNode.comments.filter((c) => c.trailing),
2865
2815
  options
2866
2816
  ),
@@ -2870,15 +2820,14 @@ function printNode(path, options, print) {
2870
2820
  const conds =
2871
2821
  armNode.conds === null
2872
2822
  ? "default"
2873
- : armPath.map(
2874
- (condPath, condIdx) =>
2875
- [",", line, print(condPath)].slice(condIdx === 0 ? 2 : 0),
2823
+ : path.map(
2824
+ ({ isFirst }) => [",", line, print()].slice(isFirst ? 2 : 0),
2876
2825
  "conds"
2877
2826
  );
2878
2827
  const body = print("body");
2879
2828
  const maybeEmptyLineBetweenArms =
2880
- armIdx > 0 &&
2881
- isPreviousLineEmpty(options.originalText, armNode, options)
2829
+ !path.isFirst &&
2830
+ isPreviousLineEmpty(options.originalText, locStart(armNode))
2882
2831
  ? hardline
2883
2832
  : "";
2884
2833
 
@@ -2894,11 +2843,11 @@ function printNode(path, options, print) {
2894
2843
  maybeTrailingComma,
2895
2844
  ...maybeTrailingComment,
2896
2845
  ]),
2897
- ].slice(armIdx > 0 ? 0 : 1);
2846
+ ].slice(!path.isFirst ? 0 : 1);
2898
2847
  }, "arms");
2899
2848
  return group([
2900
2849
  "match (",
2901
- group([softline, indent(print("cond")), softline]),
2850
+ group([indent([softline, print("cond")]), softline]),
2902
2851
  ") {",
2903
2852
  group(indent([...arms])),
2904
2853
  " ",
@@ -2908,9 +2857,7 @@ function printNode(path, options, print) {
2908
2857
  }
2909
2858
 
2910
2859
  case "noop":
2911
- return node.comments
2912
- ? comments.printComments(path.getValue().comments, options)
2913
- : "";
2860
+ return node.comments ? printComments(node.comments, options) : "";
2914
2861
  case "namedargument":
2915
2862
  return [node.name, ": ", print("value")];
2916
2863
 
@@ -2934,11 +2881,11 @@ function printNode(path, options, print) {
2934
2881
  case "variadicplaceholder":
2935
2882
  return "...";
2936
2883
 
2884
+ /* c8 ignore next 3 */
2937
2885
  case "error":
2938
2886
  default:
2939
- // istanbul ignore next
2940
- return `Have not implemented kind ${node.kind} yet.`;
2887
+ throw new Error(`Have not implemented kind '${node.kind}' yet.`);
2941
2888
  }
2942
2889
  }
2943
2890
 
2944
- module.exports = genericPrint;
2891
+ export default genericPrint;