@prettier/plugin-php 0.22.1 → 0.22.3

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 CHANGED
@@ -37,6 +37,10 @@ Prettier is an opinionated code formatter. It enforces a consistent style by par
37
37
 
38
38
  This plugin adds support for the PHP language to Prettier.
39
39
 
40
+ > [!NOTE]
41
+ >
42
+ > This plugin uses PSR / PER as guidance when making formatting decisions, but does not aim to be fully PSR / PER compliant. The idea is to stay reasonably close to how Prettier for JS works.
43
+
40
44
  ### Can this be used in production?
41
45
 
42
46
  We're considering the plugin to be stable when pure PHP files are formatted. Formatting of files that contain mixed PHP and HTML is still considered unstable - please see [open issues with the tag "inline"](https://github.com/prettier/plugin-php/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Ainline) for details.
@@ -85,7 +89,7 @@ yarn:
85
89
 
86
90
  ```bash
87
91
  yarn add --dev prettier @prettier/plugin-php
88
- # or globally
92
+ # or globally (pending https://github.com/prettier/prettier/issues/15141)
89
93
  yarn global add prettier @prettier/plugin-php
90
94
  ```
91
95
 
@@ -93,7 +97,7 @@ npm:
93
97
 
94
98
  ```bash
95
99
  npm install --save-dev prettier @prettier/plugin-php
96
- # or globally
100
+ # or globally (pending https://github.com/prettier/prettier/issues/15141)
97
101
  npm install --global prettier @prettier/plugin-php
98
102
  ```
99
103
 
@@ -270,7 +274,7 @@ Sublime Text support is available through Package Control and the [JsPrettier](h
270
274
 
271
275
  ### Vim
272
276
 
273
- Regarding plugin support in the official plugin vim-prettier see [this issue](https://github.com/prettier/vim-prettier/issues/119).
277
+ The official [prettier plugin for vim](https://github.com/prettier/vim-prettier) has built-in support for plugin-php since 1.0.
274
278
 
275
279
  #### ALE
276
280
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prettier/plugin-php",
3
- "version": "0.22.1",
3
+ "version": "0.22.3",
4
4
  "description": "Prettier PHP Plugin",
5
5
  "repository": "prettier/prettier-php",
6
6
  "author": "Lucas Azzola <@azz>",
@@ -21,7 +21,6 @@
21
21
  ],
22
22
  "dependencies": {
23
23
  "linguist-languages": "^7.27.0",
24
- "mem": "^9.0.2",
25
24
  "php-parser": "^3.1.5"
26
25
  },
27
26
  "devDependencies": {
@@ -34,13 +33,13 @@
34
33
  "@rollup/plugin-node-resolve": "^15.2.1",
35
34
  "@rollup/plugin-replace": "^5.0.5",
36
35
  "@rollup/plugin-terser": "^0.4.3",
37
- "c8": "^8.0.1",
36
+ "c8": "^9.1.0",
38
37
  "cross-env": "^7.0.2",
39
- "eslint": "8.56.0",
38
+ "eslint": "8.57.0",
40
39
  "eslint-config-prettier": "9.1.0",
41
40
  "eslint-plugin-import": "2.29.1",
42
- "eslint-plugin-jest": "27.6.0",
43
- "eslint-plugin-prettier": "5.0.1",
41
+ "eslint-plugin-jest": "27.6.3",
42
+ "eslint-plugin-prettier": "5.1.3",
44
43
  "eslint-plugin-prettier-doc": "^1.1.0",
45
44
  "jest": "29.7.0",
46
45
  "jest-environment-jsdom": "29.7.0",
package/src/options.mjs CHANGED
@@ -45,4 +45,11 @@ export default {
45
45
  { value: "1tbs", description: "Use 1tbs brace style." },
46
46
  ],
47
47
  },
48
+ singleQuote: {
49
+ since: "0.0.0",
50
+ category: CATEGORY_PHP,
51
+ type: "boolean",
52
+ default: false,
53
+ description: "Use single quotes instead of double quotes.",
54
+ },
48
55
  };
package/src/pragma.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import memoize from "mem";
1
+ import { memoize } from "./util.mjs";
2
2
  import parse from "./parser.mjs";
3
3
 
4
4
  const reHasPragma = /@prettier|@format/;
package/src/printer.mjs CHANGED
@@ -36,6 +36,7 @@ import {
36
36
  getAncestorNode,
37
37
  isReferenceLikeNode,
38
38
  normalizeMagicMethodName,
39
+ isSimpleCallArgument,
39
40
  } from "./util.mjs";
40
41
 
41
42
  const {
@@ -508,9 +509,9 @@ function printMemberChain(path, options, print) {
508
509
  printIndentedGroup(groups.slice(shouldMerge ? 2 : 1)),
509
510
  ];
510
511
 
511
- const callExpressionCount = printedNodes.filter(
512
+ const callExpressions = printedNodes.filter(
512
513
  (tuple) => tuple.node.kind === "call"
513
- ).length;
514
+ );
514
515
 
515
516
  // We don't want to print in one line if there's:
516
517
  // * A comment.
@@ -519,7 +520,10 @@ function printMemberChain(path, options, print) {
519
520
  // If the last group is a function it's okay to inline if it fits.
520
521
  if (
521
522
  hasComment ||
522
- callExpressionCount >= 3 ||
523
+ (callExpressions.length > 2 &&
524
+ callExpressions.some(
525
+ (exp) => !exp.node.arguments.every((arg) => isSimpleCallArgument(arg))
526
+ )) ||
523
527
  printedGroups.slice(0, -1).some(willBreak)
524
528
  ) {
525
529
  return group(expanded);
@@ -1014,8 +1018,8 @@ function printLines(path, options, print, childrenAttribute = "children") {
1014
1018
  "?>",
1015
1019
  ]
1016
1020
  : isProgramLikeNode(node) && isFirstNode && node.kind !== "namespace"
1017
- ? ""
1018
- : [beforeCloseTagInlineNode, "?>"];
1021
+ ? ""
1022
+ : [beforeCloseTagInlineNode, "?>"];
1019
1023
 
1020
1024
  //FIXME getNode is used to get ancestors, but it seems this means to get next sibling?
1021
1025
  const nextV = path.getNode(index + 1);
@@ -1030,8 +1034,8 @@ function printLines(path, options, print, childrenAttribute = "children") {
1030
1034
  hardline,
1031
1035
  ]
1032
1036
  : isProgramLikeNode(node) && isLastNode
1033
- ? ""
1034
- : [openTag, " "];
1037
+ ? ""
1038
+ : [openTag, " "];
1035
1039
 
1036
1040
  printed = [beforeInline, printed, afterInline];
1037
1041
  }
@@ -1087,8 +1091,8 @@ function printLines(path, options, print, childrenAttribute = "children") {
1087
1091
  : "",
1088
1092
  ]
1089
1093
  : node.comments
1090
- ? hardline
1091
- : "";
1094
+ ? hardline
1095
+ : "";
1092
1096
 
1093
1097
  parts.push(lineSuffix([beforeCloseTag, "?>"]));
1094
1098
  }
@@ -1293,17 +1297,18 @@ function printClass(path, options, print) {
1293
1297
  }
1294
1298
  }
1295
1299
 
1300
+ const hasEmptyClassBody =
1301
+ node.body && node.body.length === 0 && !hasDanglingComments(node);
1302
+
1296
1303
  const printedDeclaration = group([
1297
1304
  group(declaration),
1298
- shouldPrintHardlineForOpenBrace(options)
1305
+ shouldPrintHardlineForOpenBrace(options) && !hasEmptyClassBody
1299
1306
  ? isAnonymousClass
1300
1307
  ? line
1301
1308
  : hardline
1302
1309
  : " ",
1303
1310
  ]);
1304
1311
 
1305
- const hasEmptyClassBody =
1306
- node.body && node.body.length === 0 && !hasDanglingComments(node);
1307
1312
  const printedBody = [
1308
1313
  "{",
1309
1314
  indent([
@@ -1311,7 +1316,7 @@ function printClass(path, options, print) {
1311
1316
  printStatements(path, options, print, "body"),
1312
1317
  ]),
1313
1318
  printDanglingComments(path, options, true),
1314
- isAnonymousClass && hasEmptyClassBody ? softline : hardline,
1319
+ hasEmptyClassBody ? "" : hardline,
1315
1320
  "}",
1316
1321
  ];
1317
1322
 
@@ -1379,14 +1384,14 @@ function printFunction(path, options, print) {
1379
1384
  return [...declAttrs, printedDeclaration];
1380
1385
  }
1381
1386
 
1382
- const isClosure = node.kind === "closure";
1383
1387
  const printedBody = [
1384
1388
  "{",
1385
1389
  indent([hasEmptyBody(path) ? "" : hardline, print("body")]),
1386
- isClosure && hasEmptyBody(path) ? "" : hardline,
1390
+ hasEmptyBody(path) ? "" : hardline,
1387
1391
  "}",
1388
1392
  ];
1389
1393
 
1394
+ const isClosure = node.kind === "closure";
1390
1395
  if (isClosure) {
1391
1396
  return [...declAttrs, printedDeclaration, " ", printedBody];
1392
1397
  }
@@ -1395,7 +1400,9 @@ function printFunction(path, options, print) {
1395
1400
  return [
1396
1401
  ...declAttrs,
1397
1402
  printedDeclaration,
1398
- shouldPrintHardlineForOpenBrace(options) ? hardline : " ",
1403
+ shouldPrintHardlineForOpenBrace(options) && !hasEmptyBody(path)
1404
+ ? hardline
1405
+ : " ",
1399
1406
  printedBody,
1400
1407
  ];
1401
1408
  }
@@ -1411,7 +1418,9 @@ function printFunction(path, options, print) {
1411
1418
  conditionalGroup([
1412
1419
  [
1413
1420
  printedDeclaration,
1414
- shouldPrintHardlineForOpenBrace(options) ? hardline : " ",
1421
+ shouldPrintHardlineForOpenBrace(options) && !hasEmptyBody(path)
1422
+ ? hardline
1423
+ : " ",
1415
1424
  printedBody,
1416
1425
  ],
1417
1426
  [printedDeclaration, " ", printedBody],
@@ -1707,8 +1716,8 @@ function printNode(path, options, print) {
1707
1716
  hardline,
1708
1717
  ]
1709
1718
  : hasDanglingComments(node)
1710
- ? [line, printDanglingComments(path, options, true), line]
1711
- : "",
1719
+ ? [line, printDanglingComments(path, options, true), line]
1720
+ : "",
1712
1721
  "}",
1713
1722
  ]
1714
1723
  : "",
package/src/util.mjs CHANGED
@@ -612,6 +612,103 @@ function normalizeMagicMethodName(name) {
612
612
  return name;
613
613
  }
614
614
 
615
+ /**
616
+ * @param {string[]} kindsArray
617
+ * @returns {(node: Node | Comment) => Boolean}
618
+ */
619
+ function createTypeCheckFunction(kindsArray) {
620
+ const kinds = new Set(kindsArray);
621
+ return (node) => kinds.has(node?.kind);
622
+ }
623
+
624
+ const isSingleWordType = createTypeCheckFunction([
625
+ "variadicplaceholder",
626
+ "namedargument",
627
+ "nullkeyword",
628
+ "identifier",
629
+ "parameter",
630
+ "variable",
631
+ "variadic",
632
+ "boolean",
633
+ "literal",
634
+ "number",
635
+ "string",
636
+ "clone",
637
+ "cast",
638
+ ]);
639
+
640
+ const isArrayExpression = createTypeCheckFunction(["array"]);
641
+ const isCallLikeExpression = createTypeCheckFunction([
642
+ "nullsafepropertylookup",
643
+ "propertylookup",
644
+ "staticlookup",
645
+ "offsetlookup",
646
+ "call",
647
+ "new",
648
+ ]);
649
+ const isArrowFuncExpression = createTypeCheckFunction(["arrowfunc"]);
650
+
651
+ function getChainParts(node, prev = []) {
652
+ const parts = prev;
653
+ if (isCallLikeExpression(node)) {
654
+ parts.push(node);
655
+ }
656
+
657
+ if (!node.what) {
658
+ return parts;
659
+ }
660
+
661
+ return getChainParts(node.what, parts);
662
+ }
663
+
664
+ function isSimpleCallArgument(node, depth = 2) {
665
+ if (depth <= 0) {
666
+ return false;
667
+ }
668
+
669
+ const isChildSimple = (child) => isSimpleCallArgument(child, depth - 1);
670
+
671
+ if (isSingleWordType(node)) {
672
+ return true;
673
+ }
674
+
675
+ if (isArrayExpression(node)) {
676
+ return node.items.every((x) => x === null || isChildSimple(x));
677
+ }
678
+
679
+ if (isCallLikeExpression(node)) {
680
+ const parts = getChainParts(node);
681
+ parts.unshift();
682
+
683
+ return (
684
+ parts.length <= depth &&
685
+ parts.every((node) =>
686
+ isLookupNode(node)
687
+ ? isChildSimple(node.offset)
688
+ : node.arguments.every(isChildSimple)
689
+ )
690
+ );
691
+ }
692
+
693
+ if (isArrowFuncExpression(node)) {
694
+ return (
695
+ node.arguments.length <= depth && node.arguments.every(isChildSimple)
696
+ );
697
+ }
698
+
699
+ return false;
700
+ }
701
+
702
+ function memoize(fn) {
703
+ const cache = new Map();
704
+ return (key) => {
705
+ if (!cache.has(key)) {
706
+ cache.set(key, fn(key));
707
+ }
708
+ return cache.get(key);
709
+ };
710
+ }
711
+
615
712
  export {
616
713
  printNumber,
617
714
  getPrecedence,
@@ -641,4 +738,6 @@ export {
641
738
  isDocNode,
642
739
  getAncestorNode,
643
740
  normalizeMagicMethodName,
741
+ isSimpleCallArgument,
742
+ memoize,
644
743
  };