@prettier/plugin-php 0.24.0 → 0.26.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/README.md +1 -1
- package/package.json +16 -16
- package/src/clean.mjs +11 -0
- package/src/comments.mjs +53 -2
- package/src/needs-parens.mjs +14 -5
- package/src/options.mjs +1 -1
- package/src/printer.mjs +226 -36
- package/src/util.mjs +21 -2
- package/standalone.js +1 -1
package/README.md
CHANGED
|
@@ -198,7 +198,7 @@ supported PHP version.
|
|
|
198
198
|
You set the `phpVersion` to `composer` and this will only use the `composer.json` file to determine the php
|
|
199
199
|
version, prettier will crash if the PHP cannot be determined.
|
|
200
200
|
|
|
201
|
-
You can also set the `phpVersion` to a specific version, such as `7.4`, `8.0`, `8.1`, `8.2`, or `8.
|
|
201
|
+
You can also set the `phpVersion` to a specific version, such as `7.4`, `8.0`, `8.1`, `8.2`, `8.3` or `8.4`.
|
|
202
202
|
|
|
203
203
|
**Please Note:** If the phpVersion is not set correctly for your environment, this plugin will produce code that could
|
|
204
204
|
be incompatible with your PHP runtime. For example, if you are using PHP 7.4, but the plugin is set to PHP 8.3, it will
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prettier/plugin-php",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Prettier PHP Plugin",
|
|
5
5
|
"repository": "prettier/prettier-php",
|
|
6
6
|
"author": "Lucas Azzola <@azz>",
|
|
@@ -26,33 +26,33 @@
|
|
|
26
26
|
"index.d.ts"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"linguist-languages": "^
|
|
30
|
-
"php-parser": "^3.
|
|
29
|
+
"linguist-languages": "^9.4.0",
|
|
30
|
+
"php-parser": "^3.7.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@babel/preset-env": "^7.27.2",
|
|
34
|
-
"@rollup/plugin-alias": "^
|
|
35
|
-
"@rollup/plugin-babel": "^
|
|
36
|
-
"@rollup/plugin-commonjs": "^
|
|
34
|
+
"@rollup/plugin-alias": "^6.0.0",
|
|
35
|
+
"@rollup/plugin-babel": "^7.0.0",
|
|
36
|
+
"@rollup/plugin-commonjs": "^29.0.2",
|
|
37
37
|
"@rollup/plugin-inject": "^5.0.5",
|
|
38
38
|
"@rollup/plugin-json": "^6.1.0",
|
|
39
|
-
"@rollup/plugin-node-resolve": "^
|
|
40
|
-
"@rollup/plugin-replace": "^
|
|
39
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
40
|
+
"@rollup/plugin-replace": "^6.0.3",
|
|
41
41
|
"@rollup/plugin-terser": "^0.4.3",
|
|
42
42
|
"c8": "^10.1.3",
|
|
43
|
-
"cross-env": "^
|
|
43
|
+
"cross-env": "^10.1.0",
|
|
44
44
|
"eslint": "8.57.0",
|
|
45
|
-
"eslint-config-prettier": "
|
|
46
|
-
"eslint-plugin-import": "2.
|
|
47
|
-
"eslint-plugin-jest": "
|
|
48
|
-
"eslint-plugin-prettier": "5.
|
|
45
|
+
"eslint-config-prettier": "10.1.8",
|
|
46
|
+
"eslint-plugin-import": "2.32.0",
|
|
47
|
+
"eslint-plugin-jest": "29.15.4",
|
|
48
|
+
"eslint-plugin-prettier": "5.5.5",
|
|
49
49
|
"eslint-plugin-prettier-doc": "^1.1.0",
|
|
50
|
-
"jest": "30.0
|
|
51
|
-
"jest-environment-jsdom": "30.0
|
|
50
|
+
"jest": "30.3.0",
|
|
51
|
+
"jest-environment-jsdom": "30.3.0",
|
|
52
52
|
"jest-light-runner": "^0.7.9",
|
|
53
53
|
"jest-snapshot-serializer-raw": "^2.0.0",
|
|
54
54
|
"prettier": "^3.6.1",
|
|
55
|
-
"rollup": "^
|
|
55
|
+
"rollup": "^4.60.0",
|
|
56
56
|
"strip-ansi": "^7.1.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
package/src/clean.mjs
CHANGED
|
@@ -101,6 +101,17 @@ function clean(node, newObj) {
|
|
|
101
101
|
newObj.name.name = normalizeMagicMethodName(newObj.name.name);
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
// #[A, B] -> #[A] #[B]: the printer gives an attribute whose arguments
|
|
105
|
+
// break a block of its own (PER-CS 12.3), which is the same declaration.
|
|
106
|
+
if (Array.isArray(node.attrGroups) && node.attrGroups.length > 1) {
|
|
107
|
+
newObj.attrGroups = [
|
|
108
|
+
{
|
|
109
|
+
...newObj.attrGroups[0],
|
|
110
|
+
attrs: newObj.attrGroups.flatMap((attrGroup) => attrGroup.attrs),
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
|
|
104
115
|
if (node.kind === "noop") {
|
|
105
116
|
return null;
|
|
106
117
|
}
|
package/src/comments.mjs
CHANGED
|
@@ -62,6 +62,7 @@ function handleOwnLineComment(comment, text, options) {
|
|
|
62
62
|
options
|
|
63
63
|
) ||
|
|
64
64
|
handleTryComments(enclosingNode, followingNode, comment) ||
|
|
65
|
+
handleClassMemberStatementComments(enclosingNode, followingNode, comment) ||
|
|
65
66
|
handleClassComments(enclosingNode, followingNode, comment) ||
|
|
66
67
|
handleFunctionParameter(
|
|
67
68
|
text,
|
|
@@ -201,6 +202,7 @@ function handleRemainingComment(comment, text, options) {
|
|
|
201
202
|
handleGoto(enclosingNode, comment) ||
|
|
202
203
|
handleHalt(precedingNode, enclosingNode, followingNode, comment) ||
|
|
203
204
|
handleBreakAndContinueStatementComments(enclosingNode, comment) ||
|
|
205
|
+
handleClassMemberStatementComments(enclosingNode, followingNode, comment) ||
|
|
204
206
|
handleInlineComments(
|
|
205
207
|
enclosingNode,
|
|
206
208
|
precedingNode,
|
|
@@ -433,6 +435,32 @@ function handleTraitUseComments(enclosingNode, followingNode, comment) {
|
|
|
433
435
|
return false;
|
|
434
436
|
}
|
|
435
437
|
|
|
438
|
+
function handleClassMemberStatementComments(
|
|
439
|
+
enclosingNode,
|
|
440
|
+
followingNode,
|
|
441
|
+
comment
|
|
442
|
+
) {
|
|
443
|
+
if (
|
|
444
|
+
enclosingNode &&
|
|
445
|
+
enclosingNode.kind === "propertystatement" &&
|
|
446
|
+
enclosingNode.properties?.includes(followingNode)
|
|
447
|
+
) {
|
|
448
|
+
addLeadingComment(enclosingNode, comment);
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (
|
|
453
|
+
enclosingNode &&
|
|
454
|
+
enclosingNode.kind === "classconstant" &&
|
|
455
|
+
enclosingNode.constants?.includes(followingNode)
|
|
456
|
+
) {
|
|
457
|
+
addLeadingComment(enclosingNode, comment);
|
|
458
|
+
return true;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
|
|
436
464
|
function handleClassComments(enclosingNode, followingNode, comment) {
|
|
437
465
|
if (
|
|
438
466
|
enclosingNode &&
|
|
@@ -564,8 +592,8 @@ function handleFunctionParameter(
|
|
|
564
592
|
return false;
|
|
565
593
|
}
|
|
566
594
|
if (
|
|
567
|
-
precedingNode
|
|
568
|
-
followingNode
|
|
595
|
+
precedingNode?.kind === "typereference" &&
|
|
596
|
+
followingNode?.kind === "identifier"
|
|
569
597
|
) {
|
|
570
598
|
addTrailingComment(precedingNode, comment);
|
|
571
599
|
return true;
|
|
@@ -907,6 +935,29 @@ function getCommentChildNodes(node) {
|
|
|
907
935
|
node.what.__parent_new_arguments = [...node.arguments];
|
|
908
936
|
return [node.what];
|
|
909
937
|
}
|
|
938
|
+
|
|
939
|
+
if (node.attrGroups && node.attrGroups.length > 0) {
|
|
940
|
+
if (node.kind === "method" || node.kind === "function") {
|
|
941
|
+
// Keep every child (in source order): dropping `body` makes comments
|
|
942
|
+
// inside the body resolve against the return type, dropping `name`
|
|
943
|
+
// makes a comment after the attribute look like it precedes the body.
|
|
944
|
+
return [
|
|
945
|
+
...node.attrGroups,
|
|
946
|
+
...(node.name && typeof node.name === "object" ? [node.name] : []),
|
|
947
|
+
...node.arguments,
|
|
948
|
+
...(node.type ? [node.type] : []),
|
|
949
|
+
...(node.body ? [node.body] : []),
|
|
950
|
+
];
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
if (node.kind === "classconstant") {
|
|
954
|
+
return [...node.attrGroups, ...node.constants];
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
if (node.kind === "enumcase") {
|
|
958
|
+
return node.attrGroups;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
910
961
|
}
|
|
911
962
|
|
|
912
963
|
function canAttachComment(node) {
|
package/src/needs-parens.mjs
CHANGED
|
@@ -142,7 +142,8 @@ function needsParens(path, options) {
|
|
|
142
142
|
return false;
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
-
case "yield":
|
|
145
|
+
case "yield":
|
|
146
|
+
case "yieldfrom": {
|
|
146
147
|
switch (parent.kind) {
|
|
147
148
|
case "propertylookup":
|
|
148
149
|
case "nullsafepropertylookup":
|
|
@@ -154,8 +155,11 @@ function needsParens(path, options) {
|
|
|
154
155
|
case "retif":
|
|
155
156
|
return key === "test";
|
|
156
157
|
|
|
158
|
+
case "assign":
|
|
159
|
+
return node.kind === "yield" && !!(node.key || node.value);
|
|
160
|
+
|
|
157
161
|
default:
|
|
158
|
-
return !!(node.key || node.value);
|
|
162
|
+
return node.kind === "yieldfrom" || !!(node.key || node.value);
|
|
159
163
|
}
|
|
160
164
|
}
|
|
161
165
|
case "assign": {
|
|
@@ -166,7 +170,7 @@ function needsParens(path, options) {
|
|
|
166
170
|
return false;
|
|
167
171
|
} else if (parent.kind === "assign") {
|
|
168
172
|
return false;
|
|
169
|
-
} else if (parent.kind === "
|
|
173
|
+
} else if (parent.kind === "staticvariable") {
|
|
170
174
|
return false;
|
|
171
175
|
} else if (
|
|
172
176
|
["if", "do", "while", "foreach", "switch"].includes(parent.kind)
|
|
@@ -188,7 +192,12 @@ function needsParens(path, options) {
|
|
|
188
192
|
case "bin":
|
|
189
193
|
case "retif":
|
|
190
194
|
if (key === "test" && !parent.trueExpr) {
|
|
191
|
-
|
|
195
|
+
// A full ternary in the test position of a shorthand ternary
|
|
196
|
+
// (`?:`) needs parens: `1 ? 2 : 3 ?: 4` is a syntax error in
|
|
197
|
+
// PHP 8. Shorthand ternaries chain left-associatively, so they
|
|
198
|
+
// don't need parens here.
|
|
199
|
+
// https://github.com/prettier/plugin-php/issues/2115
|
|
200
|
+
return !!node.trueExpr;
|
|
192
201
|
}
|
|
193
202
|
|
|
194
203
|
return true;
|
|
@@ -215,7 +224,7 @@ function needsParens(path, options) {
|
|
|
215
224
|
default:
|
|
216
225
|
return false;
|
|
217
226
|
}
|
|
218
|
-
case "
|
|
227
|
+
case "silent":
|
|
219
228
|
case "cast":
|
|
220
229
|
// TODO: bug https://github.com/glayzzle/php-parser/issues/172
|
|
221
230
|
return node.parenthesizedExpression;
|
package/src/options.mjs
CHANGED
|
@@ -7,7 +7,7 @@ const CATEGORY_PHP = "PHP";
|
|
|
7
7
|
const SUPPORTED_PHP_VERSIONS = [
|
|
8
8
|
5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6,
|
|
9
9
|
7.0, 7.1, 7.2, 7.3, 7.4,
|
|
10
|
-
8.0, 8.1, 8.2, 8.3, 8.4,
|
|
10
|
+
8.0, 8.1, 8.2, 8.3, 8.4, 8.5,
|
|
11
11
|
];
|
|
12
12
|
|
|
13
13
|
export const LATEST_SUPPORTED_PHP_VERSION = Math.max(...SUPPORTED_PHP_VERSIONS);
|
package/src/printer.mjs
CHANGED
|
@@ -50,6 +50,7 @@ const {
|
|
|
50
50
|
dedent,
|
|
51
51
|
ifBreak,
|
|
52
52
|
hardline,
|
|
53
|
+
hardlineWithoutBreakParent,
|
|
53
54
|
softline,
|
|
54
55
|
literalline,
|
|
55
56
|
align,
|
|
@@ -741,6 +742,32 @@ function shouldInlineLogicalExpression(node) {
|
|
|
741
742
|
// precedence level and the AST is structured based on precedence
|
|
742
743
|
// level, things are naturally broken up correctly, i.e. `&&` is
|
|
743
744
|
// broken before `+`.
|
|
745
|
+
function printPipeChain(path, print, trailingSemicolon = false) {
|
|
746
|
+
const elements = [];
|
|
747
|
+
|
|
748
|
+
function collect() {
|
|
749
|
+
const { node } = path;
|
|
750
|
+
if (node.kind === "bin" && node.type === "|>") {
|
|
751
|
+
elements.push(path.call(print, "left"));
|
|
752
|
+
path.call(collect, "right");
|
|
753
|
+
} else {
|
|
754
|
+
elements.push(print());
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
collect();
|
|
759
|
+
|
|
760
|
+
const [first, ...rest] = elements;
|
|
761
|
+
const semicolon = trailingSemicolon
|
|
762
|
+
? ifBreak([hardlineWithoutBreakParent, ";"], ";")
|
|
763
|
+
: "";
|
|
764
|
+
return group([
|
|
765
|
+
first,
|
|
766
|
+
indent(rest.flatMap((el) => [line, "|> ", el])),
|
|
767
|
+
semicolon,
|
|
768
|
+
]);
|
|
769
|
+
}
|
|
770
|
+
|
|
744
771
|
function printBinaryExpression(
|
|
745
772
|
path,
|
|
746
773
|
print,
|
|
@@ -1172,31 +1199,16 @@ function printAttrs(path, options, print, { inline = false } = {}) {
|
|
|
1172
1199
|
if (!path.node.attrGroups) {
|
|
1173
1200
|
return [];
|
|
1174
1201
|
}
|
|
1175
|
-
path.each(() => {
|
|
1176
|
-
const attrGroup = ["#["];
|
|
1202
|
+
path.each((attrGroupPath) => {
|
|
1177
1203
|
if (!inline && allAttrs.length > 0) {
|
|
1178
1204
|
allAttrs.push(hardline);
|
|
1179
1205
|
}
|
|
1180
|
-
attrGroup.push(softline);
|
|
1181
|
-
path.each(() => {
|
|
1182
|
-
const attrNode = path.node;
|
|
1183
|
-
if (attrGroup.length > 2) {
|
|
1184
|
-
attrGroup.push(",", line);
|
|
1185
|
-
}
|
|
1186
|
-
const attrStmt = [attrNode.name];
|
|
1187
|
-
if (attrNode.args.length > 0) {
|
|
1188
|
-
attrStmt.push(printArgumentsList(path, options, print, "args"));
|
|
1189
|
-
}
|
|
1190
|
-
attrGroup.push(group(attrStmt));
|
|
1191
|
-
}, "attrs");
|
|
1192
1206
|
allAttrs.push(
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
inline ? ifBreak(softline, " ") : "",
|
|
1199
|
-
])
|
|
1207
|
+
printAllComments(
|
|
1208
|
+
attrGroupPath,
|
|
1209
|
+
() => printAttrGroup(attrGroupPath, options, print, { inline }),
|
|
1210
|
+
options
|
|
1211
|
+
)
|
|
1200
1212
|
);
|
|
1201
1213
|
}, "attrGroups");
|
|
1202
1214
|
if (allAttrs.length === 0) {
|
|
@@ -1205,6 +1217,40 @@ function printAttrs(path, options, print, { inline = false } = {}) {
|
|
|
1205
1217
|
return [...allAttrs, inline ? "" : hardline];
|
|
1206
1218
|
}
|
|
1207
1219
|
|
|
1220
|
+
// PER-CS 12.3: an attribute whose argument list is split over several lines
|
|
1221
|
+
// must be the only one in its `#[...]` block, and its arguments follow the
|
|
1222
|
+
// multiline function call rules (`#[Name(` ... `)]`). So a block is printed on
|
|
1223
|
+
// one line while it fits; otherwise each attribute gets a block of its own and
|
|
1224
|
+
// only the argument lists break.
|
|
1225
|
+
function printAttrGroup(path, options, print, { inline = false } = {}) {
|
|
1226
|
+
const printedAttrs = path.map(({ node: attrNode }) => {
|
|
1227
|
+
const attrStmt = [attrNode.name];
|
|
1228
|
+
if (attrNode.args.length > 0) {
|
|
1229
|
+
attrStmt.push(printArgumentsList(path, options, print, "args"));
|
|
1230
|
+
}
|
|
1231
|
+
return group(attrStmt);
|
|
1232
|
+
}, "attrs");
|
|
1233
|
+
const separator = inline ? ifBreak(softline, " ") : "";
|
|
1234
|
+
|
|
1235
|
+
if (printedAttrs.length === 1) {
|
|
1236
|
+
return group(["#[", printedAttrs[0], "]", separator]);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
const printedOneBlock = ["#[", join(", ", printedAttrs), "]", separator];
|
|
1240
|
+
const printedOneBlockEach = group(
|
|
1241
|
+
[
|
|
1242
|
+
join(
|
|
1243
|
+
inline ? line : hardline,
|
|
1244
|
+
printedAttrs.map((attr) => ["#[", attr, "]"])
|
|
1245
|
+
),
|
|
1246
|
+
inline ? line : "",
|
|
1247
|
+
],
|
|
1248
|
+
{ shouldBreak: true }
|
|
1249
|
+
);
|
|
1250
|
+
|
|
1251
|
+
return conditionalGroup([printedOneBlock, printedOneBlockEach]);
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1208
1254
|
function printClass(path, options, print) {
|
|
1209
1255
|
const { node } = path;
|
|
1210
1256
|
const isAnonymousClass = node.kind === "class" && node.isAnonymous;
|
|
@@ -1219,7 +1265,7 @@ function printClass(path, options, print) {
|
|
|
1219
1265
|
declaration.push("abstract ");
|
|
1220
1266
|
}
|
|
1221
1267
|
|
|
1222
|
-
if (node.isReadonly) {
|
|
1268
|
+
if (node.isReadonly && !isAnonymousClass) {
|
|
1223
1269
|
declaration.push("readonly ");
|
|
1224
1270
|
}
|
|
1225
1271
|
|
|
@@ -1431,6 +1477,38 @@ function printFunction(path, options, print) {
|
|
|
1431
1477
|
];
|
|
1432
1478
|
}
|
|
1433
1479
|
|
|
1480
|
+
// PHP 8.4 property hooks (`{ get => ...; set(...) { ... } }`) on a property or a
|
|
1481
|
+
// promoted constructor parameter. PER-CS puts the opening brace on the
|
|
1482
|
+
// declaration line and one hook per line, preserving single blank lines.
|
|
1483
|
+
function printPropertyHooks(path, options, print) {
|
|
1484
|
+
const { node } = path;
|
|
1485
|
+
|
|
1486
|
+
if (!node.hooks || node.hooks.length === 0) {
|
|
1487
|
+
return "";
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
// Interface / abstract declarations (`{ get; set; }`) stay on the property's line.
|
|
1491
|
+
if (node.hooks.every((hook) => !hook.body)) {
|
|
1492
|
+
return [" { ", join(" ", path.map(print, "hooks")), " }"];
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
const printedHooks = path.map(({ node: hook, isLast }) => {
|
|
1496
|
+
const parts = [print()];
|
|
1497
|
+
|
|
1498
|
+
if (!isLast) {
|
|
1499
|
+
parts.push(hardline);
|
|
1500
|
+
|
|
1501
|
+
if (isNextLineEmpty(options.originalText, locEnd(hook))) {
|
|
1502
|
+
parts.push(hardline);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
return parts;
|
|
1507
|
+
}, "hooks");
|
|
1508
|
+
|
|
1509
|
+
return [" {", indent([hardline, ...printedHooks]), hardline, "}"];
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1434
1512
|
function printBodyControlStructure(
|
|
1435
1513
|
path,
|
|
1436
1514
|
options,
|
|
@@ -1524,6 +1602,7 @@ function printAssignmentRight(
|
|
|
1524
1602
|
|
|
1525
1603
|
const canBreak =
|
|
1526
1604
|
(pureRightNode.kind === "bin" &&
|
|
1605
|
+
pureRightNode.type !== "|>" &&
|
|
1527
1606
|
!shouldInlineLogicalExpression(pureRightNode)) ||
|
|
1528
1607
|
(pureRightNode.kind === "retif" &&
|
|
1529
1608
|
((!pureRightNode.trueExpr &&
|
|
@@ -1738,14 +1817,13 @@ function printNode(path, options, print) {
|
|
|
1738
1817
|
node.parenthesizedExpression ? ")" : "",
|
|
1739
1818
|
];
|
|
1740
1819
|
case "parameter": {
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
}
|
|
1820
|
+
const visibilities = { 1: "public", 2: "protected", 4: "private" };
|
|
1821
|
+
// promoted constructor property: `public`, and/or the asymmetric set
|
|
1822
|
+
// visibility `private(set)` (PHP 8.4)
|
|
1823
|
+
const promoted = [
|
|
1824
|
+
node.flags ? [visibilities[node.flags], " "] : "",
|
|
1825
|
+
node.flagsSet ? [visibilities[node.flagsSet], "(set) "] : "",
|
|
1826
|
+
];
|
|
1749
1827
|
const name = [
|
|
1750
1828
|
...printAttrs(path, options, print, { inline: true }),
|
|
1751
1829
|
promoted,
|
|
@@ -1757,6 +1835,7 @@ function printNode(path, options, print) {
|
|
|
1757
1835
|
"$",
|
|
1758
1836
|
print("name"),
|
|
1759
1837
|
];
|
|
1838
|
+
const hooks = printPropertyHooks(path, options, print);
|
|
1760
1839
|
|
|
1761
1840
|
if (node.value) {
|
|
1762
1841
|
return group([
|
|
@@ -1774,10 +1853,11 @@ function printNode(path, options, print) {
|
|
|
1774
1853
|
false,
|
|
1775
1854
|
options
|
|
1776
1855
|
),
|
|
1856
|
+
hooks,
|
|
1777
1857
|
]);
|
|
1778
1858
|
}
|
|
1779
1859
|
|
|
1780
|
-
return name;
|
|
1860
|
+
return [name, hooks];
|
|
1781
1861
|
}
|
|
1782
1862
|
case "variadic":
|
|
1783
1863
|
return ["...", print("what")];
|
|
@@ -1799,7 +1879,41 @@ function printNode(path, options, print) {
|
|
|
1799
1879
|
),
|
|
1800
1880
|
]
|
|
1801
1881
|
: "",
|
|
1882
|
+
printPropertyHooks(path, options, print),
|
|
1802
1883
|
]);
|
|
1884
|
+
case "propertyhook": {
|
|
1885
|
+
const declaration = [
|
|
1886
|
+
...printAttrs(path, options, print, { inline: true }),
|
|
1887
|
+
node.isFinal ? "final " : "",
|
|
1888
|
+
node.byref ? "&" : "",
|
|
1889
|
+
node.name,
|
|
1890
|
+
node.parameter ? ["(", print("parameter"), ")"] : "",
|
|
1891
|
+
];
|
|
1892
|
+
|
|
1893
|
+
// `get;` / `set;` in an interface or abstract class
|
|
1894
|
+
if (!node.body) {
|
|
1895
|
+
return [...declaration, ";"];
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
// `get => expr;`
|
|
1899
|
+
if (node.body.kind !== "block") {
|
|
1900
|
+
return group([
|
|
1901
|
+
...declaration,
|
|
1902
|
+
" =>",
|
|
1903
|
+
printAssignmentRight(node, node.body, print("body"), false, options),
|
|
1904
|
+
";",
|
|
1905
|
+
]);
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
// `get { ... }` - like a closure, the brace stays on the hook's line
|
|
1909
|
+
return [
|
|
1910
|
+
...declaration,
|
|
1911
|
+
" {",
|
|
1912
|
+
indent([hasEmptyBody(path) ? "" : hardline, print("body")]),
|
|
1913
|
+
hasEmptyBody(path) ? "" : hardline,
|
|
1914
|
+
"}",
|
|
1915
|
+
];
|
|
1916
|
+
}
|
|
1803
1917
|
case "propertystatement": {
|
|
1804
1918
|
const attrs = [];
|
|
1805
1919
|
path.each(() => {
|
|
@@ -1822,10 +1936,18 @@ function printNode(path, options, print) {
|
|
|
1822
1936
|
|
|
1823
1937
|
return group([
|
|
1824
1938
|
...attrs,
|
|
1939
|
+
node.isAbstract ? "abstract " : "",
|
|
1940
|
+
node.isFinal ? "final " : "",
|
|
1825
1941
|
hasVisibility
|
|
1826
1942
|
? [node.visibility === null ? "var" : node.visibility, ""]
|
|
1827
1943
|
: "",
|
|
1828
|
-
|
|
1944
|
+
// asymmetric visibility: `public private(set)`
|
|
1945
|
+
node.visibilitySet
|
|
1946
|
+
? [hasVisibility ? " " : "", node.visibilitySet, "(set)"]
|
|
1947
|
+
: "",
|
|
1948
|
+
node.isStatic
|
|
1949
|
+
? [hasVisibility || node.visibilitySet ? " " : "", "static"]
|
|
1950
|
+
: "",
|
|
1829
1951
|
firstProperty ? [" ", firstProperty] : "",
|
|
1830
1952
|
indent(
|
|
1831
1953
|
printed.slice(1).map((p) => [",", hasValue ? hardline : line, p])
|
|
@@ -2094,7 +2216,7 @@ function printNode(path, options, print) {
|
|
|
2094
2216
|
() => printAttrs(path, options, print, { inline: true }),
|
|
2095
2217
|
"what"
|
|
2096
2218
|
),
|
|
2097
|
-
"class",
|
|
2219
|
+
node.what.isReadonly ? "readonly class" : "class",
|
|
2098
2220
|
node.arguments.length > 0
|
|
2099
2221
|
? [" ", printArgumentsList(path, options, print)]
|
|
2100
2222
|
: "",
|
|
@@ -2114,11 +2236,64 @@ function printNode(path, options, print) {
|
|
|
2114
2236
|
|
|
2115
2237
|
return parts;
|
|
2116
2238
|
}
|
|
2117
|
-
case "clone":
|
|
2239
|
+
case "clone": {
|
|
2240
|
+
if (!node.properties) {
|
|
2241
|
+
return [
|
|
2242
|
+
"clone ",
|
|
2243
|
+
node.what.comments ? indent(print("what")) : print("what"),
|
|
2244
|
+
];
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
// PHP 8.5 clone with: `clone($obj, ['prop' => $value])`, laid out like
|
|
2248
|
+
// a call with two arguments (see printArgumentsList). No trailing comma:
|
|
2249
|
+
// php-parser does not accept one after the properties expression.
|
|
2250
|
+
const printedWhat = print("what");
|
|
2251
|
+
const printedProperties = print("properties");
|
|
2252
|
+
const printedArguments = [printedWhat, ",", line, printedProperties];
|
|
2253
|
+
const allArgsBrokenOut = () =>
|
|
2254
|
+
group(["clone(", indent([line, ...printedArguments]), line, ")"], {
|
|
2255
|
+
shouldBreak: true,
|
|
2256
|
+
});
|
|
2257
|
+
|
|
2258
|
+
if (!shouldGroupLastArg([node.what, node.properties])) {
|
|
2259
|
+
return group(
|
|
2260
|
+
["clone(", indent([softline, ...printedArguments]), softline, ")"],
|
|
2261
|
+
{
|
|
2262
|
+
shouldBreak: willBreak(printedWhat) || willBreak(printedProperties),
|
|
2263
|
+
}
|
|
2264
|
+
);
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
const somePrintedArgumentsWillBreak =
|
|
2268
|
+
willBreak(printedWhat) || willBreak(printedProperties);
|
|
2269
|
+
const simpleConcat = [
|
|
2270
|
+
"clone(",
|
|
2271
|
+
printedWhat,
|
|
2272
|
+
", ",
|
|
2273
|
+
printedProperties,
|
|
2274
|
+
")",
|
|
2275
|
+
];
|
|
2276
|
+
|
|
2118
2277
|
return [
|
|
2119
|
-
|
|
2120
|
-
|
|
2278
|
+
somePrintedArgumentsWillBreak ? breakParent : "",
|
|
2279
|
+
conditionalGroup(
|
|
2280
|
+
[
|
|
2281
|
+
somePrintedArgumentsWillBreak
|
|
2282
|
+
? ifBreak(allArgsBrokenOut(), simpleConcat)
|
|
2283
|
+
: simpleConcat,
|
|
2284
|
+
[
|
|
2285
|
+
"clone(",
|
|
2286
|
+
printedWhat,
|
|
2287
|
+
", ",
|
|
2288
|
+
group(printedProperties, { shouldBreak: true }),
|
|
2289
|
+
")",
|
|
2290
|
+
],
|
|
2291
|
+
allArgsBrokenOut(),
|
|
2292
|
+
],
|
|
2293
|
+
{ shouldBreak: willBreak(printedWhat) }
|
|
2294
|
+
),
|
|
2121
2295
|
];
|
|
2296
|
+
}
|
|
2122
2297
|
case "propertylookup":
|
|
2123
2298
|
case "nullsafepropertylookup":
|
|
2124
2299
|
case "staticlookup":
|
|
@@ -2278,6 +2453,10 @@ function printNode(path, options, print) {
|
|
|
2278
2453
|
parent.curly) ||
|
|
2279
2454
|
(parentParent &&
|
|
2280
2455
|
parent.kind === "offsetlookup" &&
|
|
2456
|
+
// Only the base variable of the lookup follows the `${` printed
|
|
2457
|
+
// by the encapsedpart; a variable in the offset position is a
|
|
2458
|
+
// nested variable and keeps its own `$`.
|
|
2459
|
+
parent.what === node &&
|
|
2281
2460
|
parentParent.kind === "encapsedpart" &&
|
|
2282
2461
|
parentParent.syntax === "simple" &&
|
|
2283
2462
|
parentParent.curly)
|
|
@@ -2487,6 +2666,16 @@ function printNode(path, options, print) {
|
|
|
2487
2666
|
);
|
|
2488
2667
|
}
|
|
2489
2668
|
case "bin": {
|
|
2669
|
+
if (node.type === "|>") {
|
|
2670
|
+
const { parent, grandparent } = path;
|
|
2671
|
+
const isStatementLevel =
|
|
2672
|
+
parent.kind === "expressionstatement" ||
|
|
2673
|
+
(parent.kind === "assign" &&
|
|
2674
|
+
grandparent &&
|
|
2675
|
+
grandparent.kind === "expressionstatement");
|
|
2676
|
+
return printPipeChain(path, print, isStatementLevel);
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2490
2679
|
const { parent, grandparent: parentParent } = path;
|
|
2491
2680
|
const isInsideParenthesis =
|
|
2492
2681
|
node !== parent.body &&
|
|
@@ -2871,6 +3060,7 @@ function printNode(path, options, print) {
|
|
|
2871
3060
|
|
|
2872
3061
|
case "enumcase":
|
|
2873
3062
|
return group([
|
|
3063
|
+
...printAttrs(path, options, print),
|
|
2874
3064
|
"case ",
|
|
2875
3065
|
print("name"),
|
|
2876
3066
|
node.value
|
package/src/util.mjs
CHANGED
|
@@ -41,6 +41,7 @@ const PRECEDENCE = new Map(
|
|
|
41
41
|
"<<=",
|
|
42
42
|
">>=",
|
|
43
43
|
],
|
|
44
|
+
["|>"],
|
|
44
45
|
["??"],
|
|
45
46
|
["||"],
|
|
46
47
|
["&&"],
|
|
@@ -70,7 +71,7 @@ const bitshiftOperators = [">>", "<<"];
|
|
|
70
71
|
|
|
71
72
|
function isBitwiseOperator(operator) {
|
|
72
73
|
return (
|
|
73
|
-
|
|
74
|
+
bitshiftOperators.includes(operator) ||
|
|
74
75
|
operator === "|" ||
|
|
75
76
|
operator === "^" ||
|
|
76
77
|
operator === "&"
|
|
@@ -353,12 +354,30 @@ function lineShouldEndWithSemicolon(path) {
|
|
|
353
354
|
if (node.kind === "method" && node.isAbstract) {
|
|
354
355
|
return true;
|
|
355
356
|
}
|
|
357
|
+
// a hooked property ends with its closing brace, not a semicolon
|
|
358
|
+
if (
|
|
359
|
+
node.kind === "propertystatement" &&
|
|
360
|
+
node.properties.some((property) => property.hooks?.length > 0)
|
|
361
|
+
) {
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
356
364
|
if (node.kind === "method") {
|
|
357
365
|
const { parent } = path;
|
|
358
366
|
if (parent && parent.kind === "interface") {
|
|
359
367
|
return true;
|
|
360
368
|
}
|
|
361
369
|
}
|
|
370
|
+
if (node.kind === "expressionstatement") {
|
|
371
|
+
const expr = node.expression;
|
|
372
|
+
const isPipeChain =
|
|
373
|
+
(expr.kind === "bin" && expr.type === "|>") ||
|
|
374
|
+
(expr.kind === "assign" &&
|
|
375
|
+
expr.right.kind === "bin" &&
|
|
376
|
+
expr.right.type === "|>");
|
|
377
|
+
if (isPipeChain) {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
362
381
|
return [
|
|
363
382
|
"expressionstatement",
|
|
364
383
|
"do",
|
|
@@ -678,7 +697,7 @@ function isSimpleCallArgument(node, depth = 2) {
|
|
|
678
697
|
|
|
679
698
|
if (isCallLikeExpression(node)) {
|
|
680
699
|
const parts = getChainParts(node);
|
|
681
|
-
parts.
|
|
700
|
+
parts.shift();
|
|
682
701
|
|
|
683
702
|
return (
|
|
684
703
|
parts.length <= depth &&
|