From a79f730ab6e67939bb2a62ca198753314df858e1 Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Mon, 6 Jan 2025 14:27:57 +1100 Subject: [PATCH 01/21] Clean up rule documentation and code --- docs/Rules.md | 110 +++++++++++++++------------ scripts/list-rules.php | 6 +- src/Concern/DeclarationRuleTrait.php | 8 -- src/Concern/TokenRuleTrait.php | 8 -- src/Formatter.php | 6 +- src/Rule/AlignChains.php | 8 ++ src/Rule/AlignData.php | 6 ++ src/Rule/AlignLists.php | 10 +++ src/Rule/DeclarationSpacing.php | 4 +- src/Rule/HangingIndentation.php | 8 ++ src/Rule/HeredocIndentation.php | 8 +- src/Rule/IndexSpacing.php | 15 ++-- src/Rule/ListSpacing.php | 4 +- src/Rule/NormaliseComments.php | 18 ++--- src/Rule/NormaliseNumbers.php | 7 +- src/Rule/OperatorSpacing.php | 7 +- src/Rule/PlaceComments.php | 9 ++- src/Rule/Preset/WordPress.php | 2 +- src/Rule/ProtectStrings.php | 17 ++--- src/Rule/StandardSpacing.php | 24 +++--- src/Rule/StatementSpacing.php | 2 +- src/Rule/SwitchIndentation.php | 8 +- src/Rule/VerticalSpacing.php | 12 +-- 23 files changed, 169 insertions(+), 138 deletions(-) diff --git a/docs/Rules.md b/docs/Rules.md index 005998b5..d9140947 100644 --- a/docs/Rules.md +++ b/docs/Rules.md @@ -20,8 +20,8 @@ Formatting rules applied by `pretty-php` are as follows. | `PreserveOneLineStatements` | - | - | 1 | `processStatements()` | 95 | | `BlankBeforeReturn` | - | - | 1 | `processTokens()` | 97 | | `VerticalSpacing` | Y | - | 1 | `processTokens()` | 98 | -| `ListSpacing` (1) | Y | - | 1 | `processDeclarations()` | 98 | -| `ListSpacing` (2) | Y | - | 1 | `processList()` | 98 | +| `ListSpacing` (1) | Y | - | 1 | `processList()` | 98 | +| `ListSpacing` (2) | Y | - | 1 | `processDeclarations()` | 98 | | `StrictExpressions` | - | - | 1 | `processTokens()` | 98 | | `SemiStrictExpressions` | - | - | 1 | `processTokens()` | 98 | | `Drupal` (1) | - | - | 1 | `processTokens()` | 100 | @@ -61,12 +61,7 @@ Formatting rules applied by `pretty-php` are as follows. (mandatory, `processTokens()`, priority 40) -Changes to whitespace in non-constant strings are suppressed for: - -- inner siblings -- every token between square brackets - -The latter is necessary because strings like `"$foo[0]"` and `"$foo[$bar]"` are unparseable if there is any whitespace between the brackets. +In non-constant strings, whitespace between tokens is suppressed for inner siblings, and for every token between square brackets. (The latter is necessary because strings like `"$foo[0]"` and `"$foo[$bar]"` are unparseable if there is any whitespace between the brackets.) ### `NormaliseNumbers` @@ -76,7 +71,7 @@ Integer literals are normalised by replacing hexadecimal, octal and binary prefi Float literals are normalised by removing redundant zeroes, adding `0` to empty integer or fractional parts, replacing `E` with `e`, removing `+` from exponents, and expressing them with mantissae between 1.0 and 10. -If present in the input, underscores are applied to decimal values with no exponent every 3 digits, to hexadecimal values with more than 5 digits every 4 digits, and to binary values every 4 digits. +If an underscore is present in the input, underscores are applied to decimal values with no exponent every 3 digits, to hexadecimal values with more than 5 digits every 4 digits, and to binary values every 4 digits. ### `NormaliseStrings` @@ -92,11 +87,11 @@ Strings other than nowdocs are normalised as follows: (mandatory, `processTokens()`, priority 70) -In one-line C-style comments, unnecessary asterisks are removed from both delimiters, and whitespace between delimiters and adjacent content is replaced with a space. +In one-line C-style comments (`/*`), unnecessary asterisks are removed from both delimiters, the remaining content is trimmed, and spaces are added between delimiters and adjacent content. Shell-style comments (`#`) are converted to C++-style comments (`//`). -In C++-style comments, a space is added between the delimiter and adjacent content if horizontal whitespace is not already present. +In C++-style comments (`//`), a space is added between the delimiter and adjacent content if horizontal whitespace is not already present. DocBlocks are normalised for PSR-5 compliance as follows: @@ -106,39 +101,44 @@ DocBlocks are normalised for PSR-5 compliance as follows: - The content of each DocBlock is applied to its token as `COMMENT_CONTENT` data. - DocBlocks with one line of content are collapsed to a single line unless they appear to describe a file or have a subsequent named declaration. In the latter case, the `COLLAPSIBLE_COMMENT` flag is applied. -C-style comments where every line starts with an asterisk, or at least one delimiter appears on its own line, receive the same treatment as DocBlocks. +Multi-line C-style comments where every line starts with an asterisk, or at least one delimiter appears on its own line, receive the same treatment as DocBlocks. -> Any C-style comments that remain are trimmed and reindented by the renderer. +> Multi-line C-style comments that do not meet this criteria are trimmed and reindented by the renderer. ### `IndexSpacing` (mandatory, `processTokens()`, priority 78) -Leading and trailing spaces are added to tokens in the `AddSpace`, `AddSpaceBefore` and `AddSpaceAfter` indexes, then suppressed, along with adjacent blank lines, for tokens in the `SuppressSpaceBefore` and `SuppressSpaceAfter` indexes, and inside brackets other than structural and `match` braces. Blank lines are also suppressed after alternative syntax colons and before their closing counterparts. +Leading and trailing spaces are: + +- added to tokens in the `AddSpace`, `AddSpaceBefore` and `AddSpaceAfter` indexes +- suppressed, along with blank lines, for tokens in the `SuppressSpaceBefore` and `SuppressSpaceAfter` indexes, and inside brackets other than structural and `match` braces + +Blank lines are also suppressed inside alternative syntax blocks. ### `StandardSpacing` (1) (mandatory, `processTokens()`, priority 80) -If the indentation level of an open tag aligns with a tab stop, and a close tag is found in the same scope (or the document has no close tag and the open tag is in the global scope), a callback is registered to align nested tokens with it. An additional level of indentation is applied if `IndentBetweenTags` is enabled. +If the indentation level of an open tag aligns with a tab stop, and a close tag is found in the same scope (or the document has no close tag, and the open tag is in the global scope), a callback is registered to align nested tokens with it. An additional level of indentation is applied if `IndentBetweenTags` is enabled. If a `(mandatory, `processDeclarations()`, priority 80) -If a constructor has one or more promoted parameters, a line is added before every parameter. +If a constructor has one or more promoted parameters, a newline is added before every parameter. If a property has unimplemented hooks with no modifiers or attributes (e.g. `public $Foo { &get; set; }`), they are collapsed to one line, otherwise hooks with statements are formatted like anonymous functions, and hooks that use abbreviated syntax are formatted like arrow functions. @@ -154,7 +154,7 @@ Whitespace is suppressed before, and newlines are added after, semicolons in oth (mandatory, `processTokens()`, priority 80) -Operators in `declare` expressions are ignored, otherwise spaces are added before and after operators not mentioned below. +Operators in `declare` expressions are ignored. Whitespace is suppressed: @@ -163,7 +163,7 @@ Whitespace is suppressed: - before and after exception delimiters in `catch` blocks (unless strict PSR-12 mode is enabled) - after `?` in nullable types - between `++` and `--` and the variables they operate on -- after unary operators +- after other unary operators - before `:` in short ternary expressions, e.g. `$a ?: $b` A space is added: @@ -174,6 +174,8 @@ A space is added: - before and after `:` in standard ternary expressions - after `:` in other contexts +Spaces are added before and after operators not mentioned above. + ### `ControlStructureSpacing` (mandatory, `processTokens()`, priority 83) @@ -189,13 +191,13 @@ If the body of a control structure has no enclosing braces: (mandatory, `processTokens()`, priority 90) -Critical newlines are added after one-line comments with subsequent close tags. +Critical newlines are added after one-line comments followed by any token other than a close tag. Newlines are added before and after: - DocBlocks - comments with a leading newline in the input -- comments after top-level close braces if strict PSR-12 mode is enabled +- comments after top-level close braces (if strict PSR-12 mode is enabled) These comments are also saved for alignment with the next code token (unless it's a close bracket). @@ -203,7 +205,7 @@ Leading and trailing spaces are added to comments that don't appear on their own For multi-line DocBlocks, and C-style comments that receive the same treatment: -- leading blank lines are added unless the comment appears mid-statement (deferred for DocBlocks with the `COLLAPSIBLE_COMMENT` flag) +- leading blank lines are added unless the comment appears mid-statement (deferred for collapsible DocBlocks; see `DeclarationSpacing`) - trailing blank lines are added to file-level comments - trailing blank lines are suppressed for DocBlocks with subsequent code @@ -258,27 +260,19 @@ In expressions where one or more boolean operators have an adjacent newline, new In `for` loops: -- If an expression with multiple expressions breaks over multiple lines, newlines are added after comma-delimited expressions, and blank lines are added after semicolon-delimited expressions -- Otherwise, if an expression breaks over multiple lines, newlines are added after semicolon-delimited expressions -- Otherwise, if the second or third expression has a leading newline, a newline is added before the other -- Whitespace in empty expressions is suppressed +- If an expression with multiple expressions breaks over multiple lines, newlines are added after comma-delimited expressions, and blank lines are added after semicolon-delimited expressions. +- Otherwise, if an expression breaks over multiple lines, newlines are added after semicolon-delimited expressions. +- Otherwise, if the second or third expression has a leading newline, a newline is added before the other. +- Whitespace in empty expressions is suppressed. Newlines are added before open braces that belong to top-level declarations and anonymous classes declared over multiple lines. Newlines are added before both operators in ternary expressions where one operator has a leading newline. -In method chains where an object operator (`->` or `?->`) has a leading newline, newlines are added before every object operator. If the `AlignChains` rule is enabled and strict PSR-12 compliance is not, a newline is not added before the first object operator in the chain. +In method chains where an object operator (`->` or `?->`) has a leading newline, newlines are added before every object operator. If the `AlignChains` rule is enabled and strict PSR-12 compliance is not, the first object operator in the chain is excluded from this operation. ### `ListSpacing` (1) -(mandatory, `processDeclarations()`, priority 98) - -Newlines are added between comma-delimited constant declarations and property declarations. When neither `StrictLists` nor `AlignLists` are enabled, they are also added to `use` statements between comma-delimited imports and traits that break over multiple lines. - -If a list of property hooks has one or more attributes with a trailing newline, every attribute is placed on its own line, and blank lines are added before and after annotated hooks to improve readability. - -### `ListSpacing` (2) - (mandatory, `processList()`, priority 98) If interface lists break over multiple lines and neither `StrictLists` nor `AlignLists` are enabled, a newline is added before the first interface. @@ -287,6 +281,14 @@ Arrays and argument lists with trailing ("magic") commas are split into one item If parameter lists have one or more attributes with a trailing newline, every attribute is placed on its own line, and blank lines are added before and after annotated parameters to improve readability. +### `ListSpacing` (2) + +(mandatory, `processDeclarations()`, priority 98) + +Newlines are added between comma-delimited constant declarations and property declarations. When neither `StrictLists` nor `AlignLists` are enabled, they are also added to `use` statements between comma-delimited imports and trait insertions that break over multiple lines. + +If a list of property hooks has one or more attributes with a trailing newline, every attribute is placed on its own line, and blank lines are added before and after annotated hooks to improve readability. + ### `StrictExpressions` (optional, `processTokens()`, priority 98) @@ -344,7 +346,7 @@ Newlines are suppressed between parameters in function declarations that have no (optional, `processTokens()`, priority 100) -Suppression of blank lines after DocBlocks is disabled for the first DocBlock in each document. +Suppression of blank lines after DocBlocks is removed for the first DocBlock in each document. Blank lines added before DocBlocks by other rules are removed. @@ -407,10 +409,10 @@ The `Indent` and inner whitespace of each open bracket is copied to its close br In switch case lists: -- The `PreIndent` of every token is incremented -- The `Deindent` of tokens between `case` or `default` and their respective delimiters is incremented -- Newlines are added before `case` and `default` and after their respective delimiters -- Blank lines are suppressed after `case` and `default` delimiters +- The `PreIndent` of every token is incremented. +- The `Deindent` of tokens between `case` or `default` and their respective delimiters is incremented. +- Newlines are added before `case` and `default` and after their respective delimiters. +- Blank lines are suppressed after `case` and `default` delimiters. ### `DeclarationSpacing` @@ -427,7 +429,7 @@ DocBlocks in tightly-spaced groups are collapsed to a single line. Otherwise, "loose" spacing is applied by adding blank lines between declarations. -Blank lines are also added before and after each group of declarations, and they are suppressed between `use` statements, one-line `declare` statements, and property hooks not declared over multiple lines. +Blank lines are also added before and after each group of declarations. They are suppressed between `use` statements, one-line `declare` statements, and property hooks not declared over multiple lines. ### `HangingIndentation` (1) @@ -499,7 +501,12 @@ This is achieved by: (optional, _`callback`_, priority 710) -Not documented. +List items are aligned with the column after their open bracket, or with the first item in the list if they have no enclosing brackets. + +This is achieved by: + +- calculating the difference between the current and desired output columns of each item +- applying it to the `LinePadding` of the item and its adjacent tokens ### `AlignData` (2) @@ -509,6 +516,11 @@ Assignment operators are aligned unless `MaxAssignmentPadding` is not `null` and In arrays and `match` expressions, `=>` delimiters are aligned unless `MaxDoubleArrowColumn` is not `null`, in which case any found in subsequent columns are excluded from consideration. +Alignment is achieved by: + +- calculating the difference between the current and desired output columns of each token +- applying it to the `Padding` of the token + ### `HangingIndentation` (2) (mandatory, _`callback`_, priority 800) @@ -531,9 +543,7 @@ In function declarations where `)` and `{` appear at the start of consecutive li (mandatory, `beforeRender()`, priority 900) -The indentation of the first inner token of each heredoc saved earlier is applied to the heredoc by adding whitespace after newline characters in each of its tokens. - -Whitespace added to each heredoc is also applied to the `HeredocIndent` property of its `T_START_HEREDOC` token, which allows inherited indentation to be removed when processing nested heredocs. +The indentation of the first inner token of each heredoc saved earlier is applied to the heredoc by adding whitespace after newline characters in each of its tokens. (Whitespace added to each heredoc is also applied to the `HeredocIndent` property of its `T_START_HEREDOC` token, which allows inherited indentation to be removed when processing nested heredocs.) ### `PlaceComments` (2) diff --git a/scripts/list-rules.php b/scripts/list-rules.php index c305a9b3..53cad52c 100755 --- a/scripts/list-rules.php +++ b/scripts/list-rules.php @@ -141,15 +141,15 @@ function printTable(array $table): void if (is_a($rule, TokenRule::class, true)) { maybeAddRule($mainLoop, 1, $rule, $isMandatory, $isDefault, TokenRule::PROCESS_TOKENS, true, $callbackDocs); } + if (is_a($rule, ListRule::class, true)) { + maybeAddRule($mainLoop, 1, $rule, $isMandatory, $isDefault, ListRule::PROCESS_LIST, true, $callbackDocs); + } if (is_a($rule, StatementRule::class, true)) { maybeAddRule($mainLoop, 1, $rule, $isMandatory, $isDefault, StatementRule::PROCESS_STATEMENTS, true, $callbackDocs); } if (is_a($rule, DeclarationRule::class, true)) { maybeAddRule($mainLoop, 1, $rule, $isMandatory, $isDefault, DeclarationRule::PROCESS_DECLARATIONS, true, $callbackDocs); } - if (is_a($rule, ListRule::class, true)) { - maybeAddRule($mainLoop, 1, $rule, $isMandatory, $isDefault, ListRule::PROCESS_LIST, true, $callbackDocs); - } if (is_a($rule, BlockRule::class, true)) { maybeAddRule($blockLoop, 2, $rule, $isMandatory, $isDefault, BlockRule::PROCESS_BLOCK, true, $callbackDocs); } diff --git a/src/Concern/DeclarationRuleTrait.php b/src/Concern/DeclarationRuleTrait.php index c9d532e2..6d5f122a 100644 --- a/src/Concern/DeclarationRuleTrait.php +++ b/src/Concern/DeclarationRuleTrait.php @@ -20,12 +20,4 @@ public static function getDeclarationTypes(array $all): array { return ['*']; } - - /** - * @inheritDoc - */ - public static function needsSortedDeclarations(): bool - { - return true; - } } diff --git a/src/Concern/TokenRuleTrait.php b/src/Concern/TokenRuleTrait.php index 582601a6..48a90c79 100644 --- a/src/Concern/TokenRuleTrait.php +++ b/src/Concern/TokenRuleTrait.php @@ -21,12 +21,4 @@ public static function getTokens(TokenIndex $idx): array { return ['*']; } - - /** - * @inheritDoc - */ - public static function needsSortedTokens(): bool - { - return true; - } } diff --git a/src/Formatter.php b/src/Formatter.php index c72bad3b..baa7c4ac 100644 --- a/src/Formatter.php +++ b/src/Formatter.php @@ -640,6 +640,9 @@ private function apply(): self $tokenTypes[$rule] = $types; $mainLoop[$rule . '#token'] = [$rule, TokenRule::PROCESS_TOKENS, $i]; } + if (is_a($rule, ListRule::class, true)) { + $mainLoop[$rule . '#list'] = [$rule, ListRule::PROCESS_LIST, $i]; + } if (is_a($rule, StatementRule::class, true)) { $mainLoop[$rule . '#statement'] = [$rule, StatementRule::PROCESS_STATEMENTS, $i]; } @@ -655,9 +658,6 @@ private function apply(): self $declarationTypes[$rule] = $types; $mainLoop[$rule . '#declaration'] = [$rule, DeclarationRule::PROCESS_DECLARATIONS, $i]; } - if (is_a($rule, ListRule::class, true)) { - $mainLoop[$rule . '#list'] = [$rule, ListRule::PROCESS_LIST, $i]; - } if (is_a($rule, BlockRule::class, true)) { $blockLoop[$rule] = [$rule, BlockRule::PROCESS_BLOCK, $i]; } diff --git a/src/Rule/AlignChains.php b/src/Rule/AlignChains.php index 90770179..8eeecf4b 100644 --- a/src/Rule/AlignChains.php +++ b/src/Rule/AlignChains.php @@ -39,6 +39,14 @@ public static function getTokens(TokenIndex $idx): array return $idx->Chain; } + /** + * @inheritDoc + */ + public static function needsSortedTokens(): bool + { + return false; + } + /** * Apply the rule to the given tokens * diff --git a/src/Rule/AlignData.php b/src/Rule/AlignData.php index b656ef02..af9a0a2c 100644 --- a/src/Rule/AlignData.php +++ b/src/Rule/AlignData.php @@ -75,6 +75,12 @@ public function boot(): void * In arrays and `match` expressions, `=>` delimiters are aligned unless * `MaxDoubleArrowColumn` is not `null`, in which case any found in * subsequent columns are excluded from consideration. + * + * Alignment is achieved by: + * + * - calculating the difference between the current and desired output + * columns of each token + * - applying it to the `Padding` of the token */ public function processBlock(array $lines): void { diff --git a/src/Rule/AlignLists.php b/src/Rule/AlignLists.php index cfec2d50..827d8255 100644 --- a/src/Rule/AlignLists.php +++ b/src/Rule/AlignLists.php @@ -47,6 +47,16 @@ public function reset(): void * list items, along with their inner and adjacent tokens, with the column * after their open brackets, or with the first item in the list if they * have no enclosing brackets. + * + * @prettyphp-callback List items are aligned with the column after their + * open bracket, or with the first item in the list if they have no + * enclosing brackets. + * + * This is achieved by: + * + * - calculating the difference between the current and desired output + * columns of each item + * - applying it to the `LinePadding` of the item and its adjacent tokens */ public function processList(Token $parent, TokenCollection $items, Token $lastChild): void { diff --git a/src/Rule/DeclarationSpacing.php b/src/Rule/DeclarationSpacing.php index a1c95633..6c4c8542 100644 --- a/src/Rule/DeclarationSpacing.php +++ b/src/Rule/DeclarationSpacing.php @@ -86,8 +86,8 @@ public function boot(): void * Otherwise, "loose" spacing is applied by adding blank lines between * declarations. * - * Blank lines are also added before and after each group of declarations, - * and they are suppressed between `use` statements, one-line `declare` + * Blank lines are also added before and after each group of declarations. + * They are suppressed between `use` statements, one-line `declare` * statements, and property hooks not declared over multiple lines. */ public function processDeclarations(array $declarations): void diff --git a/src/Rule/HangingIndentation.php b/src/Rule/HangingIndentation.php index b26452ed..1050e8c9 100644 --- a/src/Rule/HangingIndentation.php +++ b/src/Rule/HangingIndentation.php @@ -48,6 +48,14 @@ public static function getPriority(string $method): ?int ][$method] ?? null; } + /** + * @inheritDoc + */ + public static function needsSortedTokens(): bool + { + return true; + } + /** * @inheritDoc */ diff --git a/src/Rule/HeredocIndentation.php b/src/Rule/HeredocIndentation.php index 03a55766..4b59d4e2 100644 --- a/src/Rule/HeredocIndentation.php +++ b/src/Rule/HeredocIndentation.php @@ -75,11 +75,9 @@ public function processTokens(array $tokens): void * * The indentation of the first inner token of each heredoc saved earlier is * applied to the heredoc by adding whitespace after newline characters in - * each of its tokens. - * - * Whitespace added to each heredoc is also applied to the `HeredocIndent` - * property of its `T_START_HEREDOC` token, which allows inherited - * indentation to be removed when processing nested heredocs. + * each of its tokens. (Whitespace added to each heredoc is also applied to + * the `HeredocIndent` property of its `T_START_HEREDOC` token, which allows + * inherited indentation to be removed when processing nested heredocs.) */ public function beforeRender(array $tokens): void { diff --git a/src/Rule/IndexSpacing.php b/src/Rule/IndexSpacing.php index c78d76e9..b2a343f0 100644 --- a/src/Rule/IndexSpacing.php +++ b/src/Rule/IndexSpacing.php @@ -54,12 +54,15 @@ public static function needsSortedTokens(): bool /** * Apply the rule to the given tokens * - * Leading and trailing spaces are added to tokens in the `AddSpace`, - * `AddSpaceBefore` and `AddSpaceAfter` indexes, then suppressed, along with - * adjacent blank lines, for tokens in the `SuppressSpaceBefore` and - * `SuppressSpaceAfter` indexes, and inside brackets other than structural - * and `match` braces. Blank lines are also suppressed after alternative - * syntax colons and before their closing counterparts. + * Leading and trailing spaces are: + * + * - added to tokens in the `AddSpace`, `AddSpaceBefore` and `AddSpaceAfter` + * indexes + * - suppressed, along with blank lines, for tokens in the + * `SuppressSpaceBefore` and `SuppressSpaceAfter` indexes, and inside + * brackets other than structural and `match` braces + * + * Blank lines are also suppressed inside alternative syntax blocks. */ public function processTokens(array $tokens): void { diff --git a/src/Rule/ListSpacing.php b/src/Rule/ListSpacing.php index 01600307..2ef3e108 100644 --- a/src/Rule/ListSpacing.php +++ b/src/Rule/ListSpacing.php @@ -100,7 +100,7 @@ public function processList(Token $parent, TokenCollection $items, Token $lastCh if ($lastChild->id === \T_COMMA) { $items->add($parent->CloseBracket) - ->applyWhitespace(Space::CRITICAL_LINE_BEFORE); + ->applyWhitespace(Space::LINE_BEFORE); } if ($parent->id === \T_OPEN_PARENTHESIS && $parent->isParameterList()) { @@ -114,7 +114,7 @@ public function processList(Token $parent, TokenCollection $items, Token $lastCh * Newlines are added between comma-delimited constant declarations and * property declarations. When neither `StrictLists` nor `AlignLists` are * enabled, they are also added to `use` statements between comma-delimited - * imports and traits that break over multiple lines. + * imports and trait insertions that break over multiple lines. * * If a list of property hooks has one or more attributes with a trailing * newline, every attribute is placed on its own line, and blank lines are diff --git a/src/Rule/NormaliseComments.php b/src/Rule/NormaliseComments.php index 030a6ad0..da71af76 100644 --- a/src/Rule/NormaliseComments.php +++ b/src/Rule/NormaliseComments.php @@ -50,13 +50,13 @@ public static function needsSortedTokens(): bool /** * Apply the rule to the given tokens * - * In one-line C-style comments, unnecessary asterisks are removed from both - * delimiters, and whitespace between delimiters and adjacent content is - * replaced with a space. + * In one-line C-style comments (`/*`), unnecessary asterisks are removed + * from both delimiters, the remaining content is trimmed, and spaces are + * added between delimiters and adjacent content. * * Shell-style comments (`#`) are converted to C++-style comments (`//`). * - * In C++-style comments, a space is added between the delimiter and + * In C++-style comments (`//`), a space is added between the delimiter and * adjacent content if horizontal whitespace is not already present. * * DocBlocks are normalised for PSR-5 compliance as follows: @@ -74,12 +74,12 @@ public static function needsSortedTokens(): bool * declaration. In the latter case, the `COLLAPSIBLE_COMMENT` flag is * applied. * - * C-style comments where every line starts with an asterisk, or at least - * one delimiter appears on its own line, receive the same treatment as - * DocBlocks. + * Multi-line C-style comments where every line starts with an asterisk, or + * at least one delimiter appears on its own line, receive the same + * treatment as DocBlocks. * - * > Any C-style comments that remain are trimmed and reindented by the - * > renderer. + * > Multi-line C-style comments that do not meet this criteria are trimmed + * > and reindented by the renderer. */ public function processTokens(array $tokens): void { diff --git a/src/Rule/NormaliseNumbers.php b/src/Rule/NormaliseNumbers.php index 2dda4e6b..76028b6c 100644 --- a/src/Rule/NormaliseNumbers.php +++ b/src/Rule/NormaliseNumbers.php @@ -58,9 +58,10 @@ public static function needsSortedTokens(): bool * empty integer or fractional parts, replacing `E` with `e`, removing `+` * from exponents, and expressing them with mantissae between 1.0 and 10. * - * If present in the input, underscores are applied to decimal values with - * no exponent every 3 digits, to hexadecimal values with more than 5 digits - * every 4 digits, and to binary values every 4 digits. + * If an underscore is present in the input, underscores are applied to + * decimal values with no exponent every 3 digits, to hexadecimal values + * with more than 5 digits every 4 digits, and to binary values every 4 + * digits. */ public function processTokens(array $tokens): void { diff --git a/src/Rule/OperatorSpacing.php b/src/Rule/OperatorSpacing.php index 3b9eab3a..5be88542 100644 --- a/src/Rule/OperatorSpacing.php +++ b/src/Rule/OperatorSpacing.php @@ -48,8 +48,7 @@ public static function needsSortedTokens(): bool /** * Apply the rule to the given tokens * - * Operators in `declare` expressions are ignored, otherwise spaces are - * added before and after operators not mentioned below. + * Operators in `declare` expressions are ignored. * * Whitespace is suppressed: * @@ -59,7 +58,7 @@ public static function needsSortedTokens(): bool * PSR-12 mode is enabled) * - after `?` in nullable types * - between `++` and `--` and the variables they operate on - * - after unary operators + * - after other unary operators * - before `:` in short ternary expressions, e.g. `$a ?: $b` * * A space is added: @@ -69,6 +68,8 @@ public static function needsSortedTokens(): bool * - before `?` in nullable types * - before and after `:` in standard ternary expressions * - after `:` in other contexts + * + * Spaces are added before and after operators not mentioned above. */ public function processTokens(array $tokens): void { diff --git a/src/Rule/PlaceComments.php b/src/Rule/PlaceComments.php index df55c74a..212292dc 100644 --- a/src/Rule/PlaceComments.php +++ b/src/Rule/PlaceComments.php @@ -67,14 +67,15 @@ public function reset(): void /** * Apply the rule to the given tokens * - * Critical newlines are added after one-line comments with subsequent close - * tags. + * Critical newlines are added after one-line comments followed by any token + * other than a close tag. * * Newlines are added before and after: * * - DocBlocks * - comments with a leading newline in the input - * - comments after top-level close braces if strict PSR-12 mode is enabled + * - comments after top-level close braces (if strict PSR-12 mode is + * enabled) * * These comments are also saved for alignment with the next code token * (unless it's a close bracket). @@ -88,7 +89,7 @@ public function reset(): void * treatment: * * - leading blank lines are added unless the comment appears mid-statement - * (deferred for DocBlocks with the `COLLAPSIBLE_COMMENT` flag) + * (deferred for collapsible DocBlocks; see `DeclarationSpacing`) * - trailing blank lines are added to file-level comments * - trailing blank lines are suppressed for DocBlocks with subsequent code */ diff --git a/src/Rule/Preset/WordPress.php b/src/Rule/Preset/WordPress.php index ec8679f3..051af0d0 100644 --- a/src/Rule/Preset/WordPress.php +++ b/src/Rule/Preset/WordPress.php @@ -91,7 +91,7 @@ public function reset(): void /** * Apply the rule to the given tokens * - * Suppression of blank lines after DocBlocks is disabled for the first + * Suppression of blank lines after DocBlocks is removed for the first * DocBlock in each document. * * Blank lines added before DocBlocks by other rules are removed. diff --git a/src/Rule/ProtectStrings.php b/src/Rule/ProtectStrings.php index 23e4a8ae..f2a48038 100644 --- a/src/Rule/ProtectStrings.php +++ b/src/Rule/ProtectStrings.php @@ -51,20 +51,17 @@ public static function needsSortedTokens(): bool /** * Apply the rule to the given tokens * - * Changes to whitespace in non-constant strings are suppressed for: - * - * - inner siblings - * - every token between square brackets - * - * The latter is necessary because strings like `"$foo[0]"` and - * `"$foo[$bar]"` are unparseable if there is any whitespace between the - * brackets. + * In non-constant strings, whitespace between tokens is suppressed for + * inner siblings, and for every token between square brackets. (The latter + * is necessary because strings like `"$foo[0]"` and `"$foo[$bar]"` are + * unparseable if there is any whitespace between the brackets.) */ public function processTokens(array $tokens): void { foreach ($tokens as $token) { - $next = $token->NextSibling; - if (!$next || $next->String !== $token) { + /** @var Token */ + $next = $token->NextCode; + if ($next->String !== $token) { continue; } diff --git a/src/Rule/StandardSpacing.php b/src/Rule/StandardSpacing.php index 95b95136..4a495539 100644 --- a/src/Rule/StandardSpacing.php +++ b/src/Rule/StandardSpacing.php @@ -87,7 +87,7 @@ public static function needsSortedDeclarations(): bool * Apply the rule to the given tokens * * If the indentation level of an open tag aligns with a tab stop, and a - * close tag is found in the same scope (or the document has no close tag + * close tag is found in the same scope (or the document has no close tag, * and the open tag is in the global scope), a callback is registered to * align nested tokens with it. An additional level of indentation is * applied if `IndentBetweenTags` is enabled. @@ -104,15 +104,19 @@ public static function needsSortedDeclarations(): bool * tags are suppressed. Otherwise, inner newlines are added to open and * close tags. * - * Whitespace is also applied to tokens as follows: + * Whitespace is applied to other tokens as follows: * - * - **Commas:** leading whitespace suppressed, trailing space added. - * - **`declare` statements:** whitespace suppressed between parentheses. - * - **`match` expressions:** trailing line added to delimiters after arms. - * - **Attributes:** trailing blank line suppressed, leading and trailing - * space added for parameters, property hooks, anonymous functions and - * arrow functions, leading and trailing line added for others. - * - **Heredocs:** leading line suppressed in strict PSR-12 mode. + * - **Commas:** leading whitespace is suppressed, and trailing spaces are + * added. + * - **`declare` expressions:** whitespace is suppressed between + * parentheses. + * - **`match` expressions:** newlines are added after delimiters between + * arms. + * - **Attributes:** in parameters, property hooks, anonymous functions and + * arrow functions, spaces are added before and after attributes, and + * trailing blank lines are suppressed. For other attributes, leading and + * trailing newlines are added. + * - **Heredocs:** leading newlines are suppressed in strict PSR-12 mode. * * @prettyphp-callback The `TagIndent` of tokens between indented tags is * adjusted by the difference, if any, between the open tag's indent and the @@ -334,7 +338,7 @@ static function () use ($idx, $innerIndent, $next, $last) { /** * Apply the rule to the given declarations * - * If a constructor has one or more promoted parameters, a line is added + * If a constructor has one or more promoted parameters, a newline is added * before every parameter. * * If a property has unimplemented hooks with no modifiers or attributes diff --git a/src/Rule/StatementSpacing.php b/src/Rule/StatementSpacing.php index d812a191..ad6c6555 100644 --- a/src/Rule/StatementSpacing.php +++ b/src/Rule/StatementSpacing.php @@ -63,7 +63,7 @@ public function processTokens(array $tokens): void if ($token->id === \T_COLON) { if ( !$token->CloseBracket - && !$token->isColonStatementDelimiter() + && $token->EndStatement !== $token ) { continue; } diff --git a/src/Rule/SwitchIndentation.php b/src/Rule/SwitchIndentation.php index c20f4a5c..77333901 100644 --- a/src/Rule/SwitchIndentation.php +++ b/src/Rule/SwitchIndentation.php @@ -52,12 +52,12 @@ public static function needsSortedTokens(): bool * * In switch case lists: * - * - The `PreIndent` of every token is incremented + * - The `PreIndent` of every token is incremented. * - The `Deindent` of tokens between `case` or `default` and their - * respective delimiters is incremented + * respective delimiters is incremented. * - Newlines are added before `case` and `default` and after their - * respective delimiters - * - Blank lines are suppressed after `case` and `default` delimiters + * respective delimiters. + * - Blank lines are suppressed after `case` and `default` delimiters. */ public function processTokens(array $tokens): void { diff --git a/src/Rule/VerticalSpacing.php b/src/Rule/VerticalSpacing.php index 5a7c108b..98c0b53b 100644 --- a/src/Rule/VerticalSpacing.php +++ b/src/Rule/VerticalSpacing.php @@ -148,12 +148,12 @@ public function reset(): void * * - If an expression with multiple expressions breaks over multiple lines, * newlines are added after comma-delimited expressions, and blank lines - * are added after semicolon-delimited expressions + * are added after semicolon-delimited expressions. * - Otherwise, if an expression breaks over multiple lines, newlines are - * added after semicolon-delimited expressions + * added after semicolon-delimited expressions. * - Otherwise, if the second or third expression has a leading newline, a - * newline is added before the other - * - Whitespace in empty expressions is suppressed + * newline is added before the other. + * - Whitespace in empty expressions is suppressed. * * Newlines are added before open braces that belong to top-level * declarations and anonymous classes declared over multiple lines. @@ -163,8 +163,8 @@ public function reset(): void * * In method chains where an object operator (`->` or `?->`) has a leading * newline, newlines are added before every object operator. If the - * `AlignChains` rule is enabled and strict PSR-12 compliance is not, a - * newline is not added before the first object operator in the chain. + * `AlignChains` rule is enabled and strict PSR-12 compliance is not, the + * first object operator in the chain is excluded from this operation. */ public function processTokens(array $tokens): void { From 107de690339523e9135fcfff78418012e1531938 Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Mon, 6 Jan 2025 16:27:30 +1100 Subject: [PATCH 02/21] Review rule priorities and processing order --- docs/Rules.md | 448 ++++++++++++------------- src/Formatter.php | 32 +- src/Rule/AlignArrowFunctions.php | 4 +- src/Rule/AlignChains.php | 4 +- src/Rule/AlignComments.php | 2 +- src/Rule/AlignData.php | 4 +- src/Rule/AlignLists.php | 4 +- src/Rule/AlignTernaryOperators.php | 4 +- src/Rule/BlankBeforeReturn.php | 2 +- src/Rule/ControlStructureSpacing.php | 2 +- src/Rule/DeclarationSpacing.php | 2 +- src/Rule/HangingIndentation.php | 4 +- src/Rule/HeredocIndentation.php | 4 +- src/Rule/IndexSpacing.php | 2 +- src/Rule/ListSpacing.php | 4 +- src/Rule/NormaliseComments.php | 2 +- src/Rule/NormaliseNumbers.php | 2 +- src/Rule/NormaliseStrings.php | 2 +- src/Rule/OperatorSpacing.php | 2 +- src/Rule/PlaceBraces.php | 4 +- src/Rule/PlaceComments.php | 2 +- src/Rule/PreserveNewlines.php | 2 +- src/Rule/PreserveOneLineStatements.php | 2 +- src/Rule/Preset/Drupal.php | 4 +- src/Rule/Preset/Laravel.php | 2 +- src/Rule/Preset/Symfony.php | 4 +- src/Rule/Preset/WordPress.php | 2 +- src/Rule/ProtectStrings.php | 2 +- src/Rule/SemiStrictExpressions.php | 2 +- src/Rule/StandardIndentation.php | 2 +- src/Rule/StandardSpacing.php | 6 +- src/Rule/StatementSpacing.php | 2 +- src/Rule/StrictExpressions.php | 2 +- src/Rule/StrictLists.php | 2 +- src/Rule/SwitchIndentation.php | 2 +- src/Rule/VerticalSpacing.php | 2 +- 36 files changed, 287 insertions(+), 287 deletions(-) diff --git a/docs/Rules.md b/docs/Rules.md index d9140947..ebf1428c 100644 --- a/docs/Rules.md +++ b/docs/Rules.md @@ -4,78 +4,84 @@ Formatting rules applied by `pretty-php` are as follows. | Rule | Mandatory? | Default? | Pass | Method | Priority | | --------------------------- | ---------- | -------- | ---- | ----------------------- | -------- | -| `ProtectStrings` | Y | - | 1 | `processTokens()` | 40 | -| `NormaliseNumbers` | - | Y | 1 | `processTokens()` | 60 | -| `NormaliseStrings` | - | Y | 1 | `processTokens()` | 60 | -| `NormaliseComments` | Y | - | 1 | `processTokens()` | 70 | -| `IndexSpacing` | Y | - | 1 | `processTokens()` | 78 | -| `StandardSpacing` (1) | Y | - | 1 | `processTokens()` | 80 | -| `StandardSpacing` (2) | Y | - | 1 | `processDeclarations()` | 80 | -| `StatementSpacing` | Y | - | 1 | `processTokens()` | 80 | -| `OperatorSpacing` | Y | - | 1 | `processTokens()` | 80 | -| `ControlStructureSpacing` | Y | - | 1 | `processTokens()` | 83 | -| `PlaceComments` (1) | Y | - | 1 | `processTokens()` | 90 | -| `PlaceBraces` (1) | Y | - | 1 | `processTokens()` | 92 | -| `PreserveNewlines` | - | Y | 1 | `processTokens()` | 93 | -| `PreserveOneLineStatements` | - | - | 1 | `processStatements()` | 95 | -| `BlankBeforeReturn` | - | - | 1 | `processTokens()` | 97 | -| `VerticalSpacing` | Y | - | 1 | `processTokens()` | 98 | -| `ListSpacing` (1) | Y | - | 1 | `processList()` | 98 | -| `ListSpacing` (2) | Y | - | 1 | `processDeclarations()` | 98 | -| `StrictExpressions` | - | - | 1 | `processTokens()` | 98 | -| `SemiStrictExpressions` | - | - | 1 | `processTokens()` | 98 | -| `Drupal` (1) | - | - | 1 | `processTokens()` | 100 | -| `Drupal` (2) | - | - | 1 | `processDeclarations()` | 100 | -| `Laravel` | - | - | 1 | `processTokens()` | 100 | -| `Symfony` (1) | - | - | 1 | `processTokens()` | 100 | -| `Symfony` (2) | - | - | 1 | `processList()` | 100 | -| `WordPress` | - | - | 1 | `processTokens()` | 100 | -| `AlignChains` (1) | - | - | 1 | `processTokens()` | 340 | -| `StrictLists` | - | - | 1 | `processList()` | 370 | -| `AlignArrowFunctions` (1) | - | - | 1 | `processTokens()` | 380 | -| `AlignTernaryOperators` (1) | - | - | 1 | `processTokens()` | 380 | -| `AlignLists` (1) | - | - | 1 | `processList()` | 400 | -| `StandardIndentation` | Y | - | 1 | `processTokens()` | 600 | -| `SwitchIndentation` | Y | - | 1 | `processTokens()` | 600 | -| `DeclarationSpacing` | - | Y | 1 | `processDeclarations()` | 620 | -| `HangingIndentation` (1) | Y | - | 1 | `processTokens()` | 800 | -| `HeredocIndentation` (1) | Y | - | 1 | `processTokens()` | 900 | -| `AlignData` (1) | - | - | 2 | `processBlock()` | 340 | -| `AlignComments` (1) | - | - | 2 | `processBlock()` | 340 | -| `AlignChains` (2) | - | - | 3 | _`callback`_ | 710 | -| `AlignArrowFunctions` (2) | - | - | 3 | _`callback`_ | 710 | -| `AlignTernaryOperators` (2) | - | - | 3 | _`callback`_ | 710 | -| `AlignLists` (2) | - | - | 3 | _`callback`_ | 710 | -| `AlignData` (2) | - | - | 3 | _`callback`_ | 710 | -| `HangingIndentation` (2) | Y | - | 3 | _`callback`_ | 800 | -| `StandardSpacing` (3) | Y | - | 3 | _`callback`_ | 820 | -| `PlaceBraces` (2) | Y | - | 4 | `beforeRender()` | 400 | -| `HeredocIndentation` (2) | Y | - | 4 | `beforeRender()` | 900 | +| `NormaliseComments` | Y | - | 1 | `processTokens()` | 40 | +| `NormaliseStrings` | - | Y | 1 | `processTokens()` | 42 | +| `NormaliseNumbers` | - | Y | 1 | `processTokens()` | 44 | +| `ProtectStrings` | Y | - | 1 | `processTokens()` | 60 | +| `HeredocIndentation` (1) | Y | - | 1 | `processTokens()` | 62 | +| `IndexSpacing` | Y | - | 1 | `processTokens()` | 100 | +| `OperatorSpacing` | Y | - | 1 | `processTokens()` | 102 | +| `StandardSpacing` (1) | Y | - | 1 | `processTokens()` | 104 | +| `StandardSpacing` (2) | Y | - | 1 | `processDeclarations()` | 104 | +| `StatementSpacing` | Y | - | 1 | `processTokens()` | 120 | +| `ControlStructureSpacing` | Y | - | 1 | `processTokens()` | 122 | +| `PlaceBraces` (1) | Y | - | 1 | `processTokens()` | 124 | +| `PlaceComments` (1) | Y | - | 1 | `processTokens()` | 126 | +| `PreserveNewlines` | - | Y | 1 | `processTokens()` | 200 | +| `PreserveOneLineStatements` | - | - | 1 | `processStatements()` | 202 | +| `BlankBeforeReturn` | - | - | 1 | `processTokens()` | 220 | +| `VerticalSpacing` | Y | - | 1 | `processTokens()` | 240 | +| `ListSpacing` (1) | Y | - | 1 | `processList()` | 240 | +| `ListSpacing` (2) | Y | - | 1 | `processDeclarations()` | 240 | +| `StrictLists` | - | - | 1 | `processList()` | 242 | +| `StrictExpressions` | - | - | 1 | `processTokens()` | 244 | +| `SemiStrictExpressions` | - | - | 1 | `processTokens()` | 246 | +| `AlignChains` (1) | - | - | 1 | `processTokens()` | 280 | +| `DeclarationSpacing` | - | Y | 1 | `processDeclarations()` | 299 | +| `StandardIndentation` | Y | - | 1 | `processTokens()` | 300 | +| `SwitchIndentation` | Y | - | 1 | `processTokens()` | 302 | +| `AlignArrowFunctions` (1) | - | - | 1 | `processTokens()` | 320 | +| `AlignLists` (1) | - | - | 1 | `processList()` | 322 | +| `AlignTernaryOperators` (1) | - | - | 1 | `processTokens()` | 324 | +| `HangingIndentation` (1) | Y | - | 1 | `processTokens()` | 380 | +| `Symfony` (1) | - | - | 1 | `processTokens()` | 400 | +| `Symfony` (2) | - | - | 1 | `processList()` | 400 | +| `Drupal` (1) | - | - | 1 | `processTokens()` | 420 | +| `Drupal` (2) | - | - | 1 | `processDeclarations()` | 420 | +| `Laravel` | - | - | 1 | `processTokens()` | 440 | +| `WordPress` | - | - | 1 | `processTokens()` | 480 | +| `AlignComments` (1) | - | - | 2 | `processBlock()` | 500 | +| `AlignData` (1) | - | - | 2 | `processBlock()` | 520 | +| `AlignChains` (2) | - | - | 3 | _`callback`_ | 600 | +| `AlignArrowFunctions` (2) | - | - | 3 | _`callback`_ | 600 | +| `AlignLists` (2) | - | - | 3 | _`callback`_ | 600 | +| `AlignTernaryOperators` (2) | - | - | 3 | _`callback`_ | 600 | +| `AlignData` (2) | - | - | 3 | _`callback`_ | 600 | +| `HangingIndentation` (2) | Y | - | 3 | _`callback`_ | 680 | +| `StandardSpacing` (3) | Y | - | 3 | _`callback`_ | 699 | +| `PlaceBraces` (2) | Y | - | 4 | `beforeRender()` | 920 | +| `HeredocIndentation` (2) | Y | - | 4 | `beforeRender()` | 980 | | `PlaceComments` (2) | Y | - | 4 | `beforeRender()` | 997 | | `AlignComments` (2) | - | - | 4 | `beforeRender()` | 998 | | `EssentialSpacing` | Y | - | 4 | `beforeRender()` | 999 | ## Descriptions -### `ProtectStrings` +### `NormaliseComments` (mandatory, `processTokens()`, priority 40) -In non-constant strings, whitespace between tokens is suppressed for inner siblings, and for every token between square brackets. (The latter is necessary because strings like `"$foo[0]"` and `"$foo[$bar]"` are unparseable if there is any whitespace between the brackets.) +In one-line C-style comments (`/*`), unnecessary asterisks are removed from both delimiters, the remaining content is trimmed, and spaces are added between delimiters and adjacent content. -### `NormaliseNumbers` +Shell-style comments (`#`) are converted to C++-style comments (`//`). -(default, `processTokens()`, priority 60) +In C++-style comments (`//`), a space is added between the delimiter and adjacent content if horizontal whitespace is not already present. -Integer literals are normalised by replacing hexadecimal, octal and binary prefixes with `0x`, `0` and `0b` respectively, removing redundant zeroes, and converting hexadecimal digits to uppercase. +DocBlocks are normalised for PSR-5 compliance as follows: -Float literals are normalised by removing redundant zeroes, adding `0` to empty integer or fractional parts, replacing `E` with `e`, removing `+` from exponents, and expressing them with mantissae between 1.0 and 10. +- An asterisk is added to the start of each line that doesn't have one. The indentation of undelimited lines relative to each other is maintained if possible. +- If every line starts with an asterisk and ends with `" *"` or `"\t*"`, trailing asterisks are removed. +- Trailing whitespace is removed from each line. +- The content of each DocBlock is applied to its token as `COMMENT_CONTENT` data. +- DocBlocks with one line of content are collapsed to a single line unless they appear to describe a file or have a subsequent named declaration. In the latter case, the `COLLAPSIBLE_COMMENT` flag is applied. -If an underscore is present in the input, underscores are applied to decimal values with no exponent every 3 digits, to hexadecimal values with more than 5 digits every 4 digits, and to binary values every 4 digits. +Multi-line C-style comments where every line starts with an asterisk, or at least one delimiter appears on its own line, receive the same treatment as DocBlocks. + +> Multi-line C-style comments that do not meet this criteria are trimmed and reindented by the renderer. ### `NormaliseStrings` -(default, `processTokens()`, priority 60) +(default, `processTokens()`, priority 42) Strings other than nowdocs are normalised as follows: @@ -83,31 +89,31 @@ Strings other than nowdocs are normalised as follows: - Backslash escapes are added in contexts where they improve safety, consistency and readability, otherwise they are removed if possible. - Aside from leading and continuation bytes in valid UTF-8 strings, control characters and non-ASCII characters are backslash-escaped using hexadecimal notation with lowercase digits. Invisible characters that don't belong to a recognised Unicode sequence are backslash-escaped using Unicode notation with uppercase digits. -### `NormaliseComments` +### `NormaliseNumbers` -(mandatory, `processTokens()`, priority 70) +(default, `processTokens()`, priority 44) -In one-line C-style comments (`/*`), unnecessary asterisks are removed from both delimiters, the remaining content is trimmed, and spaces are added between delimiters and adjacent content. +Integer literals are normalised by replacing hexadecimal, octal and binary prefixes with `0x`, `0` and `0b` respectively, removing redundant zeroes, and converting hexadecimal digits to uppercase. -Shell-style comments (`#`) are converted to C++-style comments (`//`). +Float literals are normalised by removing redundant zeroes, adding `0` to empty integer or fractional parts, replacing `E` with `e`, removing `+` from exponents, and expressing them with mantissae between 1.0 and 10. -In C++-style comments (`//`), a space is added between the delimiter and adjacent content if horizontal whitespace is not already present. +If an underscore is present in the input, underscores are applied to decimal values with no exponent every 3 digits, to hexadecimal values with more than 5 digits every 4 digits, and to binary values every 4 digits. -DocBlocks are normalised for PSR-5 compliance as follows: +### `ProtectStrings` -- An asterisk is added to the start of each line that doesn't have one. The indentation of undelimited lines relative to each other is maintained if possible. -- If every line starts with an asterisk and ends with `" *"` or `"\t*"`, trailing asterisks are removed. -- Trailing whitespace is removed from each line. -- The content of each DocBlock is applied to its token as `COMMENT_CONTENT` data. -- DocBlocks with one line of content are collapsed to a single line unless they appear to describe a file or have a subsequent named declaration. In the latter case, the `COLLAPSIBLE_COMMENT` flag is applied. +(mandatory, `processTokens()`, priority 60) -Multi-line C-style comments where every line starts with an asterisk, or at least one delimiter appears on its own line, receive the same treatment as DocBlocks. +In non-constant strings, whitespace between tokens is suppressed for inner siblings, and for every token between square brackets. (The latter is necessary because strings like `"$foo[0]"` and `"$foo[$bar]"` are unparseable if there is any whitespace between the brackets.) -> Multi-line C-style comments that do not meet this criteria are trimmed and reindented by the renderer. +### `HeredocIndentation` (1) + +(mandatory, `processTokens()`, priority 62) + +If `HeredocIndent` has a value other than `NONE`, heredocs are saved for later processing. ### `IndexSpacing` -(mandatory, `processTokens()`, priority 78) +(mandatory, `processTokens()`, priority 100) Leading and trailing spaces are: @@ -116,9 +122,35 @@ Leading and trailing spaces are: Blank lines are also suppressed inside alternative syntax blocks. +### `OperatorSpacing` + +(mandatory, `processTokens()`, priority 102) + +Operators in `declare` expressions are ignored. + +Whitespace is suppressed: + +- after reference-related ampersands +- before and after operators in union, intersection and DNF types +- before and after exception delimiters in `catch` blocks (unless strict PSR-12 mode is enabled) +- after `?` in nullable types +- between `++` and `--` and the variables they operate on +- after other unary operators +- before `:` in short ternary expressions, e.g. `$a ?: $b` + +A space is added: + +- before reference-related ampersands +- before DNF types that start with an open parenthesis +- before `?` in nullable types +- before and after `:` in standard ternary expressions +- after `:` in other contexts + +Spaces are added before and after operators not mentioned above. + ### `StandardSpacing` (1) -(mandatory, `processTokens()`, priority 80) +(mandatory, `processTokens()`, priority 104) If the indentation level of an open tag aligns with a tab stop, and a close tag is found in the same scope (or the document has no close tag, and the open tag is in the global scope), a callback is registered to align nested tokens with it. An additional level of indentation is applied if `IndentBetweenTags` is enabled. @@ -136,7 +168,7 @@ Whitespace is applied to other tokens as follows: ### `StandardSpacing` (2) -(mandatory, `processDeclarations()`, priority 80) +(mandatory, `processDeclarations()`, priority 104) If a constructor has one or more promoted parameters, a newline is added before every parameter. @@ -144,41 +176,15 @@ If a property has unimplemented hooks with no modifiers or attributes (e.g. `pub ### `StatementSpacing` -(mandatory, `processTokens()`, priority 80) +(mandatory, `processTokens()`, priority 120) In `for` loop expressions, a space is added after semicolons where the next expression is not empty. Whitespace is suppressed before, and newlines are added after, semicolons in other contexts and colons in alternative syntax constructs, `switch` cases and labels. -### `OperatorSpacing` - -(mandatory, `processTokens()`, priority 80) - -Operators in `declare` expressions are ignored. - -Whitespace is suppressed: - -- after reference-related ampersands -- before and after operators in union, intersection and DNF types -- before and after exception delimiters in `catch` blocks (unless strict PSR-12 mode is enabled) -- after `?` in nullable types -- between `++` and `--` and the variables they operate on -- after other unary operators -- before `:` in short ternary expressions, e.g. `$a ?: $b` - -A space is added: - -- before reference-related ampersands -- before DNF types that start with an open parenthesis -- before `?` in nullable types -- before and after `:` in standard ternary expressions -- after `:` in other contexts - -Spaces are added before and after operators not mentioned above. - ### `ControlStructureSpacing` -(mandatory, `processTokens()`, priority 83) +(mandatory, `processTokens()`, priority 122) If the body of a control structure has no enclosing braces: @@ -187,9 +193,23 @@ If the body of a control structure has no enclosing braces: - blank lines before the body are suppressed - blank lines after the body are suppressed if the control structure continues +### `PlaceBraces` (1) + +(mandatory, `processTokens()`, priority 124) + +Whitespace is applied to structural and `match` expression braces as follows: + +- Blank lines are suppressed after open braces and before close braces. +- Newlines are added after open braces. +- Newlines are added after close braces unless they belong to a `match` expression or a control structure that is immediately continued, e.g. `} else {`. In the latter case, trailing newlines are suppressed. +- Empty class, function and property hook bodies are collapsed to ` {}` on the same line as the declaration they belong to unless `CollapseEmptyDeclarationBodies` is disabled. +- Horizontal whitespace is suppressed between other empty braces. + +> Open brace placement is handled by `VerticalSpacing`, which runs after newlines are applied by other rules. + ### `PlaceComments` (1) -(mandatory, `processTokens()`, priority 90) +(mandatory, `processTokens()`, priority 126) Critical newlines are added after one-line comments followed by any token other than a close tag. @@ -209,23 +229,9 @@ For multi-line DocBlocks, and C-style comments that receive the same treatment: - trailing blank lines are added to file-level comments - trailing blank lines are suppressed for DocBlocks with subsequent code -### `PlaceBraces` (1) - -(mandatory, `processTokens()`, priority 92) - -Whitespace is applied to structural and `match` expression braces as follows: - -- Blank lines are suppressed after open braces and before close braces. -- Newlines are added after open braces. -- Newlines are added after close braces unless they belong to a `match` expression or a control structure that is immediately continued, e.g. `} else {`. In the latter case, trailing newlines are suppressed. -- Empty class, function and property hook bodies are collapsed to ` {}` on the same line as the declaration they belong to unless `CollapseEmptyDeclarationBodies` is disabled. -- Horizontal whitespace is suppressed between other empty braces. - -> Open brace placement is handled by `VerticalSpacing`, which runs after newlines are applied by other rules. - ### `PreserveNewlines` -(default, `processTokens()`, priority 93) +(default, `processTokens()`, priority 200) If a newline in the input is adjacent to a token in `AllowNewlineBefore` or `AllowNewlineAfter`, it is applied to the token as a leading or trailing newline on a best-effort basis. This has the effect of placing operators before or after newlines as per the formatter's token index. @@ -238,7 +244,7 @@ Similarly, blank lines in the input are preserved between tokens in `AllowBlankB ### `PreserveOneLineStatements` -(optional, `processStatements()`, priority 95) +(optional, `processStatements()`, priority 202) Newlines are suppressed between tokens in statements and control structures that start and end on the same line in the input. @@ -248,13 +254,13 @@ Attributes on their own line are excluded from consideration. ### `BlankBeforeReturn` -(optional, `processTokens()`, priority 97) +(optional, `processTokens()`, priority 220) Blank lines are added before non-consecutive `return`, `yield` and `yield from` statements. ### `VerticalSpacing` -(mandatory, `processTokens()`, priority 98) +(mandatory, `processTokens()`, priority 240) In expressions where one or more boolean operators have an adjacent newline, newlines are added to other boolean operators of equal or lower precedence. @@ -273,7 +279,7 @@ In method chains where an object operator (`->` or `?->`) has a leading newline, ### `ListSpacing` (1) -(mandatory, `processList()`, priority 98) +(mandatory, `processList()`, priority 240) If interface lists break over multiple lines and neither `StrictLists` nor `AlignLists` are enabled, a newline is added before the first interface. @@ -283,169 +289,171 @@ If parameter lists have one or more attributes with a trailing newline, every at ### `ListSpacing` (2) -(mandatory, `processDeclarations()`, priority 98) +(mandatory, `processDeclarations()`, priority 240) Newlines are added between comma-delimited constant declarations and property declarations. When neither `StrictLists` nor `AlignLists` are enabled, they are also added to `use` statements between comma-delimited imports and trait insertions that break over multiple lines. If a list of property hooks has one or more attributes with a trailing newline, every attribute is placed on its own line, and blank lines are added before and after annotated hooks to improve readability. +### `StrictLists` + +(optional, `processList()`, priority 242) + +Items in lists are arranged horizontally or vertically by replicating the arrangement of the first and second items. + ### `StrictExpressions` -(optional, `processTokens()`, priority 98) +(optional, `processTokens()`, priority 244) Newlines are added before and after control structure expressions that break over multiple lines. ### `SemiStrictExpressions` -(optional, `processTokens()`, priority 98) +(optional, `processTokens()`, priority 246) Newlines are added before and after control structure expressions with newlines between siblings. > Unlike `StrictExpressions`, this rule does not apply leading and trailing newlines to expressions that would not break over multiple lines if tokens between brackets were removed. -### `Drupal` (1) - -(optional, `processTokens()`, priority 100) - -Blank lines are added after DocBlocks with a `@file` tag. +### `AlignChains` (1) -Newlines are added after close braces with a subsequent `elseif`, `else`, `catch` or `finally`. +(optional, `processTokens()`, priority 280) -### `Drupal` (2) +If there are no object operators with a leading newline in a chain of method calls, or if the first object operator in the chain has a leading newline and `AlignChainAfterNewline` is disabled, no action is taken. -(optional, `processDeclarations()`, priority 100) +Otherwise, if the first object operator in the chain has a leading newline, it is removed if horizontal space on subsequent lines would be saved. Then, a callback is registered to align object operators in the chain with: -Blank lines are added inside non-empty `class`, `enum`, `interface` and `trait` braces. +- the first object operator (if it has no leading newline) +- the expression dereferenced by the first object operator (if it doesn't break over multiple lines), or +- the first token on the line before the first object operator -### `Laravel` +### `DeclarationSpacing` -(optional, `processTokens()`, priority 100) +(default, `processDeclarations()`, priority 299) -Trailing spaces are added to: +One-line declarations with a collapsed or collapsible DocBlock, or no DocBlock at all, are considered "collapsible". Declarations that break over multiple lines or have a DocBlock that cannot be collapsed to one line are considered "non-collapsible". -- `!` operators -- `fn` in arrow functions +"Tight" spacing is applied by suppressing blank lines between collapsible declarations of the same type when they appear consecutively and: -Leading and trailing spaces are suppressed for `.` operators. +- `TightDeclarationSpacing` is enabled, or +- there is no blank line in the input between the first and second declarations in the group -### `Symfony` (1) +DocBlocks in tightly-spaced groups are collapsed to a single line. -(optional, `processTokens()`, priority 100) +Otherwise, "loose" spacing is applied by adding blank lines between declarations. -Trailing spaces are added to `fn` in arrow functions. +Blank lines are also added before and after each group of declarations. They are suppressed between `use` statements, one-line `declare` statements, and property hooks not declared over multiple lines. -Leading and trailing spaces are suppressed for `.` operators. +### `StandardIndentation` -### `Symfony` (2) +(mandatory, `processTokens()`, priority 300) -(optional, `processList()`, priority 100) +The `Indent` and inner whitespace of each open bracket is copied to its close bracket, and the `Indent` of tokens between brackets with inner newlines is incremented. -Newlines are suppressed between parameters in function declarations that have no promoted constructor parameters. +### `SwitchIndentation` -### `WordPress` +(mandatory, `processTokens()`, priority 302) -(optional, `processTokens()`, priority 100) +In switch case lists: -Suppression of blank lines after DocBlocks is removed for the first DocBlock in each document. +- The `PreIndent` of every token is incremented. +- The `Deindent` of tokens between `case` or `default` and their respective delimiters is incremented. +- Newlines are added before `case` and `default` and after their respective delimiters. +- Blank lines are suppressed after `case` and `default` delimiters. -Blank lines added before DocBlocks by other rules are removed. +### `AlignArrowFunctions` (1) -Leading spaces are added to `:` in alternative syntax constructs. +(optional, `processTokens()`, priority 320) -Trailing spaces are added to `!` operators. +If an arrow function expression starts on a new line, a callback is registered to align it with the `fn` it's associated with, or with the first token on the previous line if its arguments break over multiple lines. -Suppression of blank lines inside braces is disabled. +### `AlignLists` (1) -Spaces are added inside non-empty: +(optional, `processList()`, priority 322) -- parentheses -- square brackets (except in strings or when they enclose one inner token that is not a variable) +A callback is registered to align arguments, array elements and other list items, along with their inner and adjacent tokens, with the column after their open brackets, or with the first item in the list if they have no enclosing brackets. -### `AlignChains` (1) +### `AlignTernaryOperators` (1) -(optional, `processTokens()`, priority 340) +(optional, `processTokens()`, priority 324) -If there are no object operators with a leading newline in a chain of method calls, or if the first object operator in the chain has a leading newline and `AlignChainAfterNewline` is disabled, no action is taken. +If a ternary or null coalescing operator has a leading newline, a callback is registered to align it with its expression, or with the first token on the previous line if its expression breaks over multiple lines. -Otherwise, if the first object operator in the chain has a leading newline, it is removed if horizontal space on subsequent lines would be saved. Then, a callback is registered to align object operators in the chain with: +### `HangingIndentation` (1) -- the first object operator (if it has no leading newline) -- the expression dereferenced by the first object operator (if it doesn't break over multiple lines), or -- the first token on the line before the first object operator +(mandatory, `processTokens()`, priority 380) -### `StrictLists` +Scopes and expressions that would otherwise be difficult to differentiate from adjacent code are indented for visual separation, and a callback is registered to collapse any unnecessary "overhanging" indentation levels. -(optional, `processList()`, priority 370) +### `Symfony` (1) -Items in lists are arranged horizontally or vertically by replicating the arrangement of the first and second items. +(optional, `processTokens()`, priority 400) -### `AlignArrowFunctions` (1) +Trailing spaces are added to `fn` in arrow functions. -(optional, `processTokens()`, priority 380) +Leading and trailing spaces are suppressed for `.` operators. -If an arrow function expression starts on a new line, a callback is registered to align it with the `fn` it's associated with, or with the first token on the previous line if its arguments break over multiple lines. +### `Symfony` (2) -### `AlignTernaryOperators` (1) +(optional, `processList()`, priority 400) -(optional, `processTokens()`, priority 380) +Newlines are suppressed between parameters in function declarations that have no promoted constructor parameters. -If a ternary or null coalescing operator has a leading newline, a callback is registered to align it with its expression, or with the first token on the previous line if its expression breaks over multiple lines. +### `Drupal` (1) -### `AlignLists` (1) +(optional, `processTokens()`, priority 420) -(optional, `processList()`, priority 400) +Blank lines are added after DocBlocks with a `@file` tag. -A callback is registered to align arguments, array elements and other list items, along with their inner and adjacent tokens, with the column after their open brackets, or with the first item in the list if they have no enclosing brackets. +Newlines are added after close braces with a subsequent `elseif`, `else`, `catch` or `finally`. -### `StandardIndentation` +### `Drupal` (2) -(mandatory, `processTokens()`, priority 600) +(optional, `processDeclarations()`, priority 420) -The `Indent` and inner whitespace of each open bracket is copied to its close bracket, and the `Indent` of tokens between brackets with inner newlines is incremented. +Blank lines are added inside non-empty `class`, `enum`, `interface` and `trait` braces. -### `SwitchIndentation` +### `Laravel` -(mandatory, `processTokens()`, priority 600) +(optional, `processTokens()`, priority 440) -In switch case lists: +Trailing spaces are added to: -- The `PreIndent` of every token is incremented. -- The `Deindent` of tokens between `case` or `default` and their respective delimiters is incremented. -- Newlines are added before `case` and `default` and after their respective delimiters. -- Blank lines are suppressed after `case` and `default` delimiters. +- `!` operators +- `fn` in arrow functions -### `DeclarationSpacing` +Leading and trailing spaces are suppressed for `.` operators. -(default, `processDeclarations()`, priority 620) +### `WordPress` -One-line declarations with a collapsed or collapsible DocBlock, or no DocBlock at all, are considered "collapsible". Declarations that break over multiple lines or have a DocBlock that cannot be collapsed to one line are considered "non-collapsible". +(optional, `processTokens()`, priority 480) -"Tight" spacing is applied by suppressing blank lines between collapsible declarations of the same type when they appear consecutively and: +Suppression of blank lines after DocBlocks is removed for the first DocBlock in each document. -- `TightDeclarationSpacing` is enabled, or -- there is no blank line in the input between the first and second declarations in the group +Blank lines added before DocBlocks by other rules are removed. -DocBlocks in tightly-spaced groups are collapsed to a single line. +Leading spaces are added to `:` in alternative syntax constructs. -Otherwise, "loose" spacing is applied by adding blank lines between declarations. +Trailing spaces are added to `!` operators. -Blank lines are also added before and after each group of declarations. They are suppressed between `use` statements, one-line `declare` statements, and property hooks not declared over multiple lines. +Suppression of blank lines inside braces is disabled. -### `HangingIndentation` (1) +Spaces are added inside non-empty: -(mandatory, `processTokens()`, priority 800) +- parentheses +- square brackets (except in strings or when they enclose one inner token that is not a variable) -Scopes and expressions that would otherwise be difficult to differentiate from adjacent code are indented for visual separation, and a callback is registered to collapse any unnecessary "overhanging" indentation levels. +### `AlignComments` (1) -### `HeredocIndentation` (1) +(optional, `processBlock()`, priority 500) -(mandatory, `processTokens()`, priority 900) +Comments beside code, along with any continuations on subsequent lines, are saved for alignment. -If `HeredocIndent` has a value other than `NONE`, heredocs are saved for later processing. +C++- and shell-style comments on their own line after a comment beside code are treated as continuations of the initial comment if they are of the same type and were indented by at least one column relative to code in the same context. ### `AlignData` (1) -(optional, `processBlock()`, priority 340) +(optional, `processBlock()`, priority 520) When they appear in the same scope, a callback is registered to align consecutive: @@ -455,17 +463,9 @@ When they appear in the same scope, a callback is registered to align consecutiv If the open bracket of an array is not followed by a newline and neither `AlignLists` nor `StrictLists` are enabled, its `=>` delimiters are ignored. -### `AlignComments` (1) - -(optional, `processBlock()`, priority 340) - -Comments beside code, along with any continuations on subsequent lines, are saved for alignment. - -C++- and shell-style comments on their own line after a comment beside code are treated as continuations of the initial comment if they are of the same type and were indented by at least one column relative to code in the same context. - ### `AlignChains` (2) -(optional, _`callback`_, priority 710) +(optional, _`callback`_, priority 600) Object operators in a chain of method calls are aligned with a given token. @@ -477,7 +477,7 @@ This is achieved by: ### `AlignArrowFunctions` (2) -(optional, _`callback`_, priority 710) +(optional, _`callback`_, priority 600) Tokens in arrow function expressions are aligned with the `fn` they're associated with, or with the first token on the previous line if its arguments break over multiple lines. @@ -486,31 +486,31 @@ This is achieved by: - calculating the difference between the current and desired output columns of the first token in the expression - applying it to the `LinePadding` of each token -### `AlignTernaryOperators` (2) +### `AlignLists` (2) -(optional, _`callback`_, priority 710) +(optional, _`callback`_, priority 600) -Ternary and null coalescing operators with leading newlines are aligned with their expressions, or with the first token on the previous line if their expressions break over multiple lines. +List items are aligned with the column after their open bracket, or with the first item in the list if they have no enclosing brackets. This is achieved by: -- calculating the difference between the current and desired output columns of the operator -- applying it to the `LinePadding` of the operator and its adjacent tokens +- calculating the difference between the current and desired output columns of each item +- applying it to the `LinePadding` of the item and its adjacent tokens -### `AlignLists` (2) +### `AlignTernaryOperators` (2) -(optional, _`callback`_, priority 710) +(optional, _`callback`_, priority 600) -List items are aligned with the column after their open bracket, or with the first item in the list if they have no enclosing brackets. +Ternary and null coalescing operators with leading newlines are aligned with their expressions, or with the first token on the previous line if their expressions break over multiple lines. This is achieved by: -- calculating the difference between the current and desired output columns of each item -- applying it to the `LinePadding` of the item and its adjacent tokens +- calculating the difference between the current and desired output columns of the operator +- applying it to the `LinePadding` of the operator and its adjacent tokens ### `AlignData` (2) -(optional, _`callback`_, priority 710) +(optional, _`callback`_, priority 600) Assignment operators are aligned unless `MaxAssignmentPadding` is not `null` and would be exceeded. @@ -523,25 +523,25 @@ Alignment is achieved by: ### `HangingIndentation` (2) -(mandatory, _`callback`_, priority 800) +(mandatory, _`callback`_, priority 680) "Overhanging" indentation applied earlier is collapsed to the minimum level required to ensure distinct scopes and expressions do not appear to run together. ### `StandardSpacing` (3) -(mandatory, _`callback`_, priority 820) +(mandatory, _`callback`_, priority 699) The `TagIndent` of tokens between indented tags is adjusted by the difference, if any, between the open tag's indent and the indentation level of the first token after the open tag. ### `PlaceBraces` (2) -(mandatory, `beforeRender()`, priority 400) +(mandatory, `beforeRender()`, priority 920) In function declarations where `)` and `{` appear at the start of consecutive lines, they are collapsed to the same line. ### `HeredocIndentation` (2) -(mandatory, `beforeRender()`, priority 900) +(mandatory, `beforeRender()`, priority 980) The indentation of the first inner token of each heredoc saved earlier is applied to the heredoc by adding whitespace after newline characters in each of its tokens. (Whitespace added to each heredoc is also applied to the `HeredocIndent` property of its `T_START_HEREDOC` token, which allows inherited indentation to be removed when processing nested heredocs.) diff --git a/src/Formatter.php b/src/Formatter.php index baa7c4ac..355b4100 100644 --- a/src/Formatter.php +++ b/src/Formatter.php @@ -246,25 +246,25 @@ final class Formatter implements Buildable, Immutable * @var array> */ public const DEFAULT_RULES = [ - ProtectStrings::class, - NormaliseNumbers::class, - NormaliseStrings::class, NormaliseComments::class, + NormaliseStrings::class, + NormaliseNumbers::class, + ProtectStrings::class, + HeredocIndentation::class, IndexSpacing::class, + OperatorSpacing::class, StandardSpacing::class, StatementSpacing::class, - OperatorSpacing::class, ControlStructureSpacing::class, - PlaceComments::class, PlaceBraces::class, + PlaceComments::class, PreserveNewlines::class, VerticalSpacing::class, ListSpacing::class, + DeclarationSpacing::class, StandardIndentation::class, SwitchIndentation::class, - DeclarationSpacing::class, HangingIndentation::class, - HeredocIndentation::class, EssentialSpacing::class, ]; @@ -272,25 +272,25 @@ final class Formatter implements Buildable, Immutable * @var array> */ public const OPTIONAL_RULES = [ - NormaliseNumbers::class, NormaliseStrings::class, + NormaliseNumbers::class, PreserveNewlines::class, PreserveOneLineStatements::class, BlankBeforeReturn::class, + StrictLists::class, StrictExpressions::class, SemiStrictExpressions::class, - Drupal::class, - Laravel::class, - Symfony::class, - WordPress::class, AlignChains::class, - StrictLists::class, + DeclarationSpacing::class, AlignArrowFunctions::class, - AlignTernaryOperators::class, AlignLists::class, - AlignData::class, + AlignTernaryOperators::class, + Symfony::class, + Drupal::class, + Laravel::class, + WordPress::class, AlignComments::class, - DeclarationSpacing::class, + AlignData::class, ]; /** diff --git a/src/Rule/AlignArrowFunctions.php b/src/Rule/AlignArrowFunctions.php index b01f78dc..d84b2df6 100644 --- a/src/Rule/AlignArrowFunctions.php +++ b/src/Rule/AlignArrowFunctions.php @@ -23,8 +23,8 @@ final class AlignArrowFunctions implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 380, - self::CALLBACK => 710, + self::PROCESS_TOKENS => 320, + self::CALLBACK => 600, ][$method] ?? null; } diff --git a/src/Rule/AlignChains.php b/src/Rule/AlignChains.php index 8eeecf4b..fe00f002 100644 --- a/src/Rule/AlignChains.php +++ b/src/Rule/AlignChains.php @@ -26,8 +26,8 @@ final class AlignChains implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 340, - self::CALLBACK => 710, + self::PROCESS_TOKENS => 280, + self::CALLBACK => 600, ][$method] ?? null; } diff --git a/src/Rule/AlignComments.php b/src/Rule/AlignComments.php index e3e763f1..3b0f1e9d 100644 --- a/src/Rule/AlignComments.php +++ b/src/Rule/AlignComments.php @@ -26,7 +26,7 @@ final class AlignComments implements BlockRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_BLOCK => 340, + self::PROCESS_BLOCK => 500, self::BEFORE_RENDER => 998, ][$method] ?? null; } diff --git a/src/Rule/AlignData.php b/src/Rule/AlignData.php index af9a0a2c..d2b381de 100644 --- a/src/Rule/AlignData.php +++ b/src/Rule/AlignData.php @@ -32,8 +32,8 @@ final class AlignData implements BlockRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_BLOCK => 340, - self::CALLBACK => 710, + self::PROCESS_BLOCK => 520, + self::CALLBACK => 600, ][$method] ?? null; } diff --git a/src/Rule/AlignLists.php b/src/Rule/AlignLists.php index 827d8255..af2fc6d0 100644 --- a/src/Rule/AlignLists.php +++ b/src/Rule/AlignLists.php @@ -27,8 +27,8 @@ final class AlignLists implements ListRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_LIST => 400, - self::CALLBACK => 710, + self::PROCESS_LIST => 322, + self::CALLBACK => 600, ][$method] ?? null; } diff --git a/src/Rule/AlignTernaryOperators.php b/src/Rule/AlignTernaryOperators.php index 741c87c0..676e7476 100644 --- a/src/Rule/AlignTernaryOperators.php +++ b/src/Rule/AlignTernaryOperators.php @@ -25,8 +25,8 @@ final class AlignTernaryOperators implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 380, - self::CALLBACK => 710, + self::PROCESS_TOKENS => 324, + self::CALLBACK => 600, ][$method] ?? null; } diff --git a/src/Rule/BlankBeforeReturn.php b/src/Rule/BlankBeforeReturn.php index 90b43749..4e2fdeb8 100644 --- a/src/Rule/BlankBeforeReturn.php +++ b/src/Rule/BlankBeforeReturn.php @@ -22,7 +22,7 @@ final class BlankBeforeReturn implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 97, + self::PROCESS_TOKENS => 220, ][$method] ?? null; } diff --git a/src/Rule/ControlStructureSpacing.php b/src/Rule/ControlStructureSpacing.php index 3c6d0dd3..77e64299 100644 --- a/src/Rule/ControlStructureSpacing.php +++ b/src/Rule/ControlStructureSpacing.php @@ -25,7 +25,7 @@ final class ControlStructureSpacing implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 83, + self::PROCESS_TOKENS => 122, ][$method] ?? null; } diff --git a/src/Rule/DeclarationSpacing.php b/src/Rule/DeclarationSpacing.php index 6c4c8542..a9ae2503 100644 --- a/src/Rule/DeclarationSpacing.php +++ b/src/Rule/DeclarationSpacing.php @@ -34,7 +34,7 @@ final class DeclarationSpacing implements DeclarationRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_DECLARATIONS => 620, + self::PROCESS_DECLARATIONS => 299, ][$method] ?? null; } diff --git a/src/Rule/HangingIndentation.php b/src/Rule/HangingIndentation.php index 1050e8c9..aa16731d 100644 --- a/src/Rule/HangingIndentation.php +++ b/src/Rule/HangingIndentation.php @@ -43,8 +43,8 @@ final class HangingIndentation implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 800, - self::CALLBACK => 800, + self::PROCESS_TOKENS => 380, + self::CALLBACK => 680, ][$method] ?? null; } diff --git a/src/Rule/HeredocIndentation.php b/src/Rule/HeredocIndentation.php index 4b59d4e2..2b2a9eb8 100644 --- a/src/Rule/HeredocIndentation.php +++ b/src/Rule/HeredocIndentation.php @@ -26,8 +26,8 @@ final class HeredocIndentation implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 900, - self::BEFORE_RENDER => 900, + self::PROCESS_TOKENS => 62, + self::BEFORE_RENDER => 980, ][$method] ?? null; } diff --git a/src/Rule/IndexSpacing.php b/src/Rule/IndexSpacing.php index b2a343f0..02bf6e7b 100644 --- a/src/Rule/IndexSpacing.php +++ b/src/Rule/IndexSpacing.php @@ -23,7 +23,7 @@ final class IndexSpacing implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 78, + self::PROCESS_TOKENS => 100, ][$method] ?? null; } diff --git a/src/Rule/ListSpacing.php b/src/Rule/ListSpacing.php index 2ef3e108..3528f33b 100644 --- a/src/Rule/ListSpacing.php +++ b/src/Rule/ListSpacing.php @@ -30,8 +30,8 @@ final class ListSpacing implements ListRule, DeclarationRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_LIST => 98, - self::PROCESS_DECLARATIONS => 98, + self::PROCESS_LIST => 240, + self::PROCESS_DECLARATIONS => 240, ][$method] ?? null; } diff --git a/src/Rule/NormaliseComments.php b/src/Rule/NormaliseComments.php index da71af76..65cfd3ba 100644 --- a/src/Rule/NormaliseComments.php +++ b/src/Rule/NormaliseComments.php @@ -27,7 +27,7 @@ final class NormaliseComments implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 70, + self::PROCESS_TOKENS => 40, ][$method] ?? null; } diff --git a/src/Rule/NormaliseNumbers.php b/src/Rule/NormaliseNumbers.php index 76028b6c..bcb18158 100644 --- a/src/Rule/NormaliseNumbers.php +++ b/src/Rule/NormaliseNumbers.php @@ -24,7 +24,7 @@ final class NormaliseNumbers implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 60, + self::PROCESS_TOKENS => 44, ][$method] ?? null; } diff --git a/src/Rule/NormaliseStrings.php b/src/Rule/NormaliseStrings.php index 34ad5cab..0fb7b091 100644 --- a/src/Rule/NormaliseStrings.php +++ b/src/Rule/NormaliseStrings.php @@ -29,7 +29,7 @@ final class NormaliseStrings implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 60, + self::PROCESS_TOKENS => 42, ][$method] ?? null; } diff --git a/src/Rule/OperatorSpacing.php b/src/Rule/OperatorSpacing.php index 5be88542..cd913026 100644 --- a/src/Rule/OperatorSpacing.php +++ b/src/Rule/OperatorSpacing.php @@ -25,7 +25,7 @@ final class OperatorSpacing implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 80, + self::PROCESS_TOKENS => 102, ][$method] ?? null; } diff --git a/src/Rule/PlaceBraces.php b/src/Rule/PlaceBraces.php index 457bf5df..ba87a9ac 100644 --- a/src/Rule/PlaceBraces.php +++ b/src/Rule/PlaceBraces.php @@ -27,8 +27,8 @@ final class PlaceBraces implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 92, - self::BEFORE_RENDER => 400, + self::PROCESS_TOKENS => 124, + self::BEFORE_RENDER => 920, ][$method] ?? null; } diff --git a/src/Rule/PlaceComments.php b/src/Rule/PlaceComments.php index 212292dc..ea4c5892 100644 --- a/src/Rule/PlaceComments.php +++ b/src/Rule/PlaceComments.php @@ -33,7 +33,7 @@ final class PlaceComments implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 90, + self::PROCESS_TOKENS => 126, self::BEFORE_RENDER => 997, ][$method] ?? null; } diff --git a/src/Rule/PreserveNewlines.php b/src/Rule/PreserveNewlines.php index eddf20f5..a0fb9bb3 100644 --- a/src/Rule/PreserveNewlines.php +++ b/src/Rule/PreserveNewlines.php @@ -29,7 +29,7 @@ final class PreserveNewlines implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 93, + self::PROCESS_TOKENS => 200, ][$method] ?? null; } diff --git a/src/Rule/PreserveOneLineStatements.php b/src/Rule/PreserveOneLineStatements.php index c177af4f..b1c8d077 100644 --- a/src/Rule/PreserveOneLineStatements.php +++ b/src/Rule/PreserveOneLineStatements.php @@ -22,7 +22,7 @@ final class PreserveOneLineStatements implements StatementRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_STATEMENTS => 95, + self::PROCESS_STATEMENTS => 202, ][$method] ?? null; } diff --git a/src/Rule/Preset/Drupal.php b/src/Rule/Preset/Drupal.php index 85d2853c..d018741f 100644 --- a/src/Rule/Preset/Drupal.php +++ b/src/Rule/Preset/Drupal.php @@ -47,8 +47,8 @@ public static function getFormatter(int $flags = 0): Formatter public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 100, - self::PROCESS_DECLARATIONS => 100, + self::PROCESS_TOKENS => 420, + self::PROCESS_DECLARATIONS => 420, ][$method] ?? null; } diff --git a/src/Rule/Preset/Laravel.php b/src/Rule/Preset/Laravel.php index 33134ef9..9ee3a1c4 100644 --- a/src/Rule/Preset/Laravel.php +++ b/src/Rule/Preset/Laravel.php @@ -42,7 +42,7 @@ public static function getFormatter(int $flags = 0): Formatter public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 100, + self::PROCESS_TOKENS => 440, ][$method] ?? null; } diff --git a/src/Rule/Preset/Symfony.php b/src/Rule/Preset/Symfony.php index 473fd471..7c042050 100644 --- a/src/Rule/Preset/Symfony.php +++ b/src/Rule/Preset/Symfony.php @@ -51,8 +51,8 @@ public static function getFormatter(int $flags = 0): Formatter public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 100, - self::PROCESS_LIST => 100, + self::PROCESS_TOKENS => 400, + self::PROCESS_LIST => 400, ][$method] ?? null; } diff --git a/src/Rule/Preset/WordPress.php b/src/Rule/Preset/WordPress.php index 051af0d0..76973ffd 100644 --- a/src/Rule/Preset/WordPress.php +++ b/src/Rule/Preset/WordPress.php @@ -52,7 +52,7 @@ public static function getFormatter(int $flags = 0): Formatter public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 100, + self::PROCESS_TOKENS => 480, ][$method] ?? null; } diff --git a/src/Rule/ProtectStrings.php b/src/Rule/ProtectStrings.php index f2a48038..70af24b2 100644 --- a/src/Rule/ProtectStrings.php +++ b/src/Rule/ProtectStrings.php @@ -24,7 +24,7 @@ final class ProtectStrings implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 40, + self::PROCESS_TOKENS => 60, ][$method] ?? null; } diff --git a/src/Rule/SemiStrictExpressions.php b/src/Rule/SemiStrictExpressions.php index a24760f2..8cdd57c4 100644 --- a/src/Rule/SemiStrictExpressions.php +++ b/src/Rule/SemiStrictExpressions.php @@ -24,7 +24,7 @@ final class SemiStrictExpressions implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 98, + self::PROCESS_TOKENS => 246, ][$method] ?? null; } diff --git a/src/Rule/StandardIndentation.php b/src/Rule/StandardIndentation.php index a43e83c8..6c38facc 100644 --- a/src/Rule/StandardIndentation.php +++ b/src/Rule/StandardIndentation.php @@ -21,7 +21,7 @@ final class StandardIndentation implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 600, + self::PROCESS_TOKENS => 300, ][$method] ?? null; } diff --git a/src/Rule/StandardSpacing.php b/src/Rule/StandardSpacing.php index 4a495539..16924caf 100644 --- a/src/Rule/StandardSpacing.php +++ b/src/Rule/StandardSpacing.php @@ -32,9 +32,9 @@ final class StandardSpacing implements TokenRule, DeclarationRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 80, - self::PROCESS_DECLARATIONS => 80, - self::CALLBACK => 820, + self::PROCESS_TOKENS => 104, + self::PROCESS_DECLARATIONS => 104, + self::CALLBACK => 699, ][$method] ?? null; } diff --git a/src/Rule/StatementSpacing.php b/src/Rule/StatementSpacing.php index ad6c6555..195feeda 100644 --- a/src/Rule/StatementSpacing.php +++ b/src/Rule/StatementSpacing.php @@ -23,7 +23,7 @@ final class StatementSpacing implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 80, + self::PROCESS_TOKENS => 120, ][$method] ?? null; } diff --git a/src/Rule/StrictExpressions.php b/src/Rule/StrictExpressions.php index 112fab50..dae5cf42 100644 --- a/src/Rule/StrictExpressions.php +++ b/src/Rule/StrictExpressions.php @@ -24,7 +24,7 @@ final class StrictExpressions implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 98, + self::PROCESS_TOKENS => 244, ][$method] ?? null; } diff --git a/src/Rule/StrictLists.php b/src/Rule/StrictLists.php index 5dbc5869..275fbfcb 100644 --- a/src/Rule/StrictLists.php +++ b/src/Rule/StrictLists.php @@ -23,7 +23,7 @@ final class StrictLists implements ListRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_LIST => 370, + self::PROCESS_LIST => 242, ][$method] ?? null; } diff --git a/src/Rule/SwitchIndentation.php b/src/Rule/SwitchIndentation.php index 77333901..06f96cd9 100644 --- a/src/Rule/SwitchIndentation.php +++ b/src/Rule/SwitchIndentation.php @@ -23,7 +23,7 @@ final class SwitchIndentation implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 600, + self::PROCESS_TOKENS => 302, ][$method] ?? null; } diff --git a/src/Rule/VerticalSpacing.php b/src/Rule/VerticalSpacing.php index 98c0b53b..b835fe22 100644 --- a/src/Rule/VerticalSpacing.php +++ b/src/Rule/VerticalSpacing.php @@ -35,7 +35,7 @@ final class VerticalSpacing implements TokenRule public static function getPriority(string $method): ?int { return [ - self::PROCESS_TOKENS => 98, + self::PROCESS_TOKENS => 240, ][$method] ?? null; } From c8f2437f733a0347c2dfaa9c06c9156c6ff8b8d9 Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Mon, 6 Jan 2025 21:27:11 +1100 Subject: [PATCH 03/21] Rename `HeredocIndentation`, merge `ListSpacing` into `VerticalSpacing` --- docs/Rules.md | 58 ++--- src/Formatter.php | 6 +- ...edocIndentation.php => FormatHeredocs.php} | 2 +- src/Rule/ListSpacing.php | 202 ------------------ src/Rule/VerticalSpacing.php | 171 ++++++++++++++- tests/unit/Rule/ListSpacingTest.php | 46 ---- tests/unit/Rule/VerticalSpacingTest.php | 22 ++ 7 files changed, 224 insertions(+), 283 deletions(-) rename src/Rule/{HeredocIndentation.php => FormatHeredocs.php} (98%) delete mode 100644 src/Rule/ListSpacing.php delete mode 100644 tests/unit/Rule/ListSpacingTest.php diff --git a/docs/Rules.md b/docs/Rules.md index ebf1428c..859bcc2c 100644 --- a/docs/Rules.md +++ b/docs/Rules.md @@ -8,7 +8,7 @@ Formatting rules applied by `pretty-php` are as follows. | `NormaliseStrings` | - | Y | 1 | `processTokens()` | 42 | | `NormaliseNumbers` | - | Y | 1 | `processTokens()` | 44 | | `ProtectStrings` | Y | - | 1 | `processTokens()` | 60 | -| `HeredocIndentation` (1) | Y | - | 1 | `processTokens()` | 62 | +| `FormatHeredocs` (1) | Y | - | 1 | `processTokens()` | 62 | | `IndexSpacing` | Y | - | 1 | `processTokens()` | 100 | | `OperatorSpacing` | Y | - | 1 | `processTokens()` | 102 | | `StandardSpacing` (1) | Y | - | 1 | `processTokens()` | 104 | @@ -20,9 +20,9 @@ Formatting rules applied by `pretty-php` are as follows. | `PreserveNewlines` | - | Y | 1 | `processTokens()` | 200 | | `PreserveOneLineStatements` | - | - | 1 | `processStatements()` | 202 | | `BlankBeforeReturn` | - | - | 1 | `processTokens()` | 220 | -| `VerticalSpacing` | Y | - | 1 | `processTokens()` | 240 | -| `ListSpacing` (1) | Y | - | 1 | `processList()` | 240 | -| `ListSpacing` (2) | Y | - | 1 | `processDeclarations()` | 240 | +| `VerticalSpacing` (1) | Y | - | 1 | `processTokens()` | 240 | +| `VerticalSpacing` (2) | Y | - | 1 | `processList()` | 240 | +| `VerticalSpacing` (3) | Y | - | 1 | `processDeclarations()` | 240 | | `StrictLists` | - | - | 1 | `processList()` | 242 | | `StrictExpressions` | - | - | 1 | `processTokens()` | 244 | | `SemiStrictExpressions` | - | - | 1 | `processTokens()` | 246 | @@ -50,7 +50,7 @@ Formatting rules applied by `pretty-php` are as follows. | `HangingIndentation` (2) | Y | - | 3 | _`callback`_ | 680 | | `StandardSpacing` (3) | Y | - | 3 | _`callback`_ | 699 | | `PlaceBraces` (2) | Y | - | 4 | `beforeRender()` | 920 | -| `HeredocIndentation` (2) | Y | - | 4 | `beforeRender()` | 980 | +| `FormatHeredocs` (2) | Y | - | 4 | `beforeRender()` | 980 | | `PlaceComments` (2) | Y | - | 4 | `beforeRender()` | 997 | | `AlignComments` (2) | - | - | 4 | `beforeRender()` | 998 | | `EssentialSpacing` | Y | - | 4 | `beforeRender()` | 999 | @@ -105,7 +105,7 @@ If an underscore is present in the input, underscores are applied to decimal val In non-constant strings, whitespace between tokens is suppressed for inner siblings, and for every token between square brackets. (The latter is necessary because strings like `"$foo[0]"` and `"$foo[$bar]"` are unparseable if there is any whitespace between the brackets.) -### `HeredocIndentation` (1) +### `FormatHeredocs` (1) (mandatory, `processTokens()`, priority 62) @@ -258,7 +258,7 @@ Attributes on their own line are excluded from consideration. Blank lines are added before non-consecutive `return`, `yield` and `yield from` statements. -### `VerticalSpacing` +### `VerticalSpacing` (1) (mandatory, `processTokens()`, priority 240) @@ -277,7 +277,7 @@ Newlines are added before both operators in ternary expressions where one operat In method chains where an object operator (`->` or `?->`) has a leading newline, newlines are added before every object operator. If the `AlignChains` rule is enabled and strict PSR-12 compliance is not, the first object operator in the chain is excluded from this operation. -### `ListSpacing` (1) +### `VerticalSpacing` (2) (mandatory, `processList()`, priority 240) @@ -287,7 +287,7 @@ Arrays and argument lists with trailing ("magic") commas are split into one item If parameter lists have one or more attributes with a trailing newline, every attribute is placed on its own line, and blank lines are added before and after annotated parameters to improve readability. -### `ListSpacing` (2) +### `VerticalSpacing` (3) (mandatory, `processDeclarations()`, priority 240) @@ -539,7 +539,7 @@ The `TagIndent` of tokens between indented tags is adjusted by the difference, i In function declarations where `)` and `{` appear at the start of consecutive lines, they are collapsed to the same line. -### `HeredocIndentation` (2) +### `FormatHeredocs` (2) (mandatory, `beforeRender()`, priority 980) @@ -617,7 +617,7 @@ Newlines and spaces are added after tokens that would otherwise fail to parse. T | `T_QUESTION` | `AlignTernaryOperators`, `VerticalSpacing` | | `T_RETURN` | `BlankBeforeReturn` | | `T_SEMICOLON` | `StatementSpacing` | -| `T_START_HEREDOC` | `HeredocIndentation`, `ProtectStrings`, `StandardSpacing` | +| `T_START_HEREDOC` | `FormatHeredocs`, `ProtectStrings`, `StandardSpacing` | | `T_SWITCH` | `SemiStrictExpressions`, `StrictExpressions`, `SwitchIndentation` | | `T_WHILE` | `ControlStructureSpacing`, `SemiStrictExpressions`, `StrictExpressions` | | `T_XOR` | `VerticalSpacing` | @@ -626,21 +626,21 @@ Newlines and spaces are added after tokens that would otherwise fail to parse. T ## `DeclarationRule` classes, by declaration type -| Declaration | Rules | -| -------------- | ------------------------------------------------------ | -| `CASE` | `DeclarationSpacing` | -| `CLASS` | `DeclarationSpacing`, `Drupal` | -| `CONST` | `DeclarationSpacing`, `ListSpacing` | -| `DECLARE` | `DeclarationSpacing` | -| `ENUM` | `DeclarationSpacing`, `Drupal` | -| `FUNCTION` | `DeclarationSpacing` | -| `HOOK` | `DeclarationSpacing` | -| `INTERFACE` | `DeclarationSpacing`, `Drupal` | -| `NAMESPACE` | `DeclarationSpacing` | -| `PARAM` | `ListSpacing`, `StandardSpacing` | -| `PROPERTY` | `DeclarationSpacing`, `ListSpacing`, `StandardSpacing` | -| `TRAIT` | `DeclarationSpacing`, `Drupal` | -| `USE` | `DeclarationSpacing`, `ListSpacing` | -| `USE_CONST` | `DeclarationSpacing`, `ListSpacing` | -| `USE_FUNCTION` | `DeclarationSpacing`, `ListSpacing` | -| `USE_TRAIT` | `DeclarationSpacing`, `ListSpacing` | +| Declaration | Rules | +| -------------- | ---------------------------------------------------------- | +| `CASE` | `DeclarationSpacing` | +| `CLASS` | `DeclarationSpacing`, `Drupal` | +| `CONST` | `DeclarationSpacing`, `VerticalSpacing` | +| `DECLARE` | `DeclarationSpacing` | +| `ENUM` | `DeclarationSpacing`, `Drupal` | +| `FUNCTION` | `DeclarationSpacing` | +| `HOOK` | `DeclarationSpacing` | +| `INTERFACE` | `DeclarationSpacing`, `Drupal` | +| `NAMESPACE` | `DeclarationSpacing` | +| `PARAM` | `StandardSpacing`, `VerticalSpacing` | +| `PROPERTY` | `DeclarationSpacing`, `StandardSpacing`, `VerticalSpacing` | +| `TRAIT` | `DeclarationSpacing`, `Drupal` | +| `USE` | `DeclarationSpacing`, `VerticalSpacing` | +| `USE_CONST` | `DeclarationSpacing`, `VerticalSpacing` | +| `USE_FUNCTION` | `DeclarationSpacing`, `VerticalSpacing` | +| `USE_TRAIT` | `DeclarationSpacing`, `VerticalSpacing` | diff --git a/src/Formatter.php b/src/Formatter.php index 355b4100..1b5a468c 100644 --- a/src/Formatter.php +++ b/src/Formatter.php @@ -50,10 +50,9 @@ use Lkrms\PrettyPHP\Rule\ControlStructureSpacing; use Lkrms\PrettyPHP\Rule\DeclarationSpacing; use Lkrms\PrettyPHP\Rule\EssentialSpacing; +use Lkrms\PrettyPHP\Rule\FormatHeredocs; use Lkrms\PrettyPHP\Rule\HangingIndentation; -use Lkrms\PrettyPHP\Rule\HeredocIndentation; use Lkrms\PrettyPHP\Rule\IndexSpacing; -use Lkrms\PrettyPHP\Rule\ListSpacing; use Lkrms\PrettyPHP\Rule\NormaliseComments; use Lkrms\PrettyPHP\Rule\NormaliseNumbers; use Lkrms\PrettyPHP\Rule\NormaliseStrings; @@ -250,7 +249,7 @@ final class Formatter implements Buildable, Immutable NormaliseStrings::class, NormaliseNumbers::class, ProtectStrings::class, - HeredocIndentation::class, + FormatHeredocs::class, IndexSpacing::class, OperatorSpacing::class, StandardSpacing::class, @@ -260,7 +259,6 @@ final class Formatter implements Buildable, Immutable PlaceComments::class, PreserveNewlines::class, VerticalSpacing::class, - ListSpacing::class, DeclarationSpacing::class, StandardIndentation::class, SwitchIndentation::class, diff --git a/src/Rule/HeredocIndentation.php b/src/Rule/FormatHeredocs.php similarity index 98% rename from src/Rule/HeredocIndentation.php rename to src/Rule/FormatHeredocs.php index 2b2a9eb8..887db76f 100644 --- a/src/Rule/HeredocIndentation.php +++ b/src/Rule/FormatHeredocs.php @@ -13,7 +13,7 @@ * * @api */ -final class HeredocIndentation implements TokenRule +final class FormatHeredocs implements TokenRule { use TokenRuleTrait; diff --git a/src/Rule/ListSpacing.php b/src/Rule/ListSpacing.php deleted file mode 100644 index 3528f33b..00000000 --- a/src/Rule/ListSpacing.php +++ /dev/null @@ -1,202 +0,0 @@ - 240, - self::PROCESS_DECLARATIONS => 240, - ][$method] ?? null; - } - - /** - * @inheritDoc - */ - public static function getDeclarationTypes(array $all): array - { - return [ - Type::_CONST => true, - Type::_USE => true, - Type::PROPERTY => true, - Type::PARAM => true, - Type::USE_CONST => true, - Type::USE_FUNCTION => true, - Type::USE_TRAIT => true, - ]; - } - - /** - * @inheritDoc - */ - public static function needsSortedDeclarations(): bool - { - return false; - } - - /** - * @inheritDoc - */ - public function boot(): void - { - $this->ListRuleEnabled = $this->Formatter->Enabled[StrictLists::class] - ?? $this->Formatter->Enabled[AlignLists::class] - ?? false; - } - - /** - * Apply the rule to a token and the list of items associated with it - * - * If interface lists break over multiple lines and neither `StrictLists` - * nor `AlignLists` are enabled, a newline is added before the first - * interface. - * - * Arrays and argument lists with trailing ("magic") commas are split into - * one item per line. - * - * If parameter lists have one or more attributes with a trailing newline, - * every attribute is placed on its own line, and blank lines are added - * before and after annotated parameters to improve readability. - */ - public function processList(Token $parent, TokenCollection $items, Token $lastChild): void - { - if (!$parent->CloseBracket) { - if ( - !$this->ListRuleEnabled - && ($parent->id === \T_EXTENDS || $parent->id === \T_IMPLEMENTS) - && $items->tokenHasNewlineBefore() - ) { - /** @var Token */ - $token = $items->first(); - $token->applyWhitespace(Space::LINE_BEFORE); - } - return; - } - - if ($lastChild->id === \T_COMMA) { - $items->add($parent->CloseBracket) - ->applyWhitespace(Space::LINE_BEFORE); - } - - if ($parent->id === \T_OPEN_PARENTHESIS && $parent->isParameterList()) { - $this->normaliseDeclarationList($items); - } - } - - /** - * Apply the rule to the given declarations - * - * Newlines are added between comma-delimited constant declarations and - * property declarations. When neither `StrictLists` nor `AlignLists` are - * enabled, they are also added to `use` statements between comma-delimited - * imports and trait insertions that break over multiple lines. - * - * If a list of property hooks has one or more attributes with a trailing - * newline, every attribute is placed on its own line, and blank lines are - * added before and after annotated hooks to improve readability. - */ - public function processDeclarations(array $declarations): void - { - foreach ($declarations as $token) { - $type = $token->Data[TokenData::NAMED_DECLARATION_TYPE]; - - if ( - $type === Type::_CONST - || $type === Type::PROPERTY - || $type & Type::_USE - ) { - $commas = $token->withNextSiblings($token->EndStatement) - ->getAnyOf(\T_COMMA); - if (!($type & Type::_USE) || ( - !$this->ListRuleEnabled - && $commas->tokenHasNewlineBeforeNextCode() - )) { - $commas->applyWhitespace(Space::LINE_AFTER); - } - } - - if ($type & Type::PROPERTY) { - /** @var TokenCollection */ - $hooks = $token->Data[TokenData::PROPERTY_HOOKS]; - if ($hooks->count()) { - $this->normaliseDeclarationList($hooks); - } - } - } - } - - /** - * @param iterable $items - */ - private function normaliseDeclarationList(iterable $items): void - { - $hasAttributeWithNewline = false; - foreach ($items as $item) { - $attributes = $item->withNextSiblingsFrom($this->Idx->Attribute, true); - $itemTokens[$item->index] = $attributes; - if ( - $attributes->tokenHasNewlineAfter(true) - || $attributes->shift()->tokenHasNewlineBefore() - ) { - $hasAttributeWithNewline = true; - break; - } - } - if (!$hasAttributeWithNewline) { - return; - } - - $addBlankBefore = false; - $i = 0; - foreach ($items as $item) { - if ($addBlankBefore) { - $item->applyBlankBefore(true); - $addBlankBefore = false; - $hasBlankBefore = true; - } else { - $hasBlankBefore = false; - } - $tokens = $itemTokens[$item->index] - ?? $item->withNextSiblingsFrom($this->Idx->Attribute, true); - $tokens[] = $item->skipNextSiblingFrom($this->Idx->Attribute); - foreach ($tokens as $token) { - $token->applyWhitespace(Space::LINE_BEFORE); - if ($this->Idx->Attribute[$token->id]) { - $token = $token->CloseBracket ?? $token; - $token->Whitespace |= Space::LINE_AFTER; - // Add a blank line before each item with an attribute, and - // another before the next item - $addBlankBefore = true; - } - } - if ($i++ && $addBlankBefore && !$hasBlankBefore) { - $item->applyBlankBefore(true); - } - } - } -} diff --git a/src/Rule/VerticalSpacing.php b/src/Rule/VerticalSpacing.php index b835fe22..9b1c2df2 100644 --- a/src/Rule/VerticalSpacing.php +++ b/src/Rule/VerticalSpacing.php @@ -2,11 +2,17 @@ namespace Lkrms\PrettyPHP\Rule; +use Lkrms\PrettyPHP\Catalog\DeclarationType as Type; use Lkrms\PrettyPHP\Catalog\TokenData; use Lkrms\PrettyPHP\Catalog\TokenFlag; use Lkrms\PrettyPHP\Catalog\WhitespaceFlag as Space; +use Lkrms\PrettyPHP\Concern\DeclarationRuleTrait; +use Lkrms\PrettyPHP\Concern\ListRuleTrait; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; +use Lkrms\PrettyPHP\Contract\DeclarationRule; +use Lkrms\PrettyPHP\Contract\ListRule; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\Internal\TokenCollection; use Lkrms\PrettyPHP\Token; use Lkrms\PrettyPHP\TokenIndex; use Lkrms\PrettyPHP\TokenUtil; @@ -17,11 +23,14 @@ * * @api */ -final class VerticalSpacing implements TokenRule +final class VerticalSpacing implements TokenRule, ListRule, DeclarationRule { use TokenRuleTrait; + use ListRuleTrait; + use DeclarationRuleTrait; private bool $AlignChainsEnabled; + private bool $ListRuleEnabled; /** @var array */ private array $HasNewline; /** @var array */ @@ -36,6 +45,8 @@ public static function getPriority(string $method): ?int { return [ self::PROCESS_TOKENS => 240, + self::PROCESS_LIST => 240, + self::PROCESS_DECLARATIONS => 240, ][$method] ?? null; } @@ -63,6 +74,30 @@ public static function needsSortedTokens(): bool return false; } + /** + * @inheritDoc + */ + public static function getDeclarationTypes(array $all): array + { + return [ + Type::_CONST => true, + Type::_USE => true, + Type::PROPERTY => true, + Type::PARAM => true, + Type::USE_CONST => true, + Type::USE_FUNCTION => true, + Type::USE_TRAIT => true, + ]; + } + + /** + * @inheritDoc + */ + public static function needsSortedDeclarations(): bool + { + return false; + } + /** * @inheritDoc */ @@ -70,6 +105,9 @@ public function boot(): void { $this->AlignChainsEnabled = $this->Formatter->Enabled[AlignChains::class] ?? false; + $this->ListRuleEnabled = $this->Formatter->Enabled[StrictLists::class] + ?? $this->Formatter->Enabled[AlignLists::class] + ?? false; $hasNewlineBefore = fn(Token $t): bool => $t->hasNewlineAfterPrevCode(); $hasNewlineAfter = fn(Token $t): bool => $t->hasNewlineBeforeNextCode(); @@ -347,4 +385,135 @@ public function processTokens(array $tokens): void } } } + + /** + * Apply the rule to a token and the list of items associated with it + * + * If interface lists break over multiple lines and neither `StrictLists` + * nor `AlignLists` are enabled, a newline is added before the first + * interface. + * + * Arrays and argument lists with trailing ("magic") commas are split into + * one item per line. + * + * If parameter lists have one or more attributes with a trailing newline, + * every attribute is placed on its own line, and blank lines are added + * before and after annotated parameters to improve readability. + */ + public function processList(Token $parent, TokenCollection $items, Token $lastChild): void + { + if (!$parent->CloseBracket) { + if ( + !$this->ListRuleEnabled + && ($parent->id === \T_EXTENDS || $parent->id === \T_IMPLEMENTS) + && $items->tokenHasNewlineBefore() + ) { + /** @var Token */ + $token = $items->first(); + $token->applyWhitespace(Space::LINE_BEFORE); + } + return; + } + + if ($lastChild->id === \T_COMMA) { + $items->add($parent->CloseBracket) + ->applyWhitespace(Space::LINE_BEFORE); + } + + if ($parent->id === \T_OPEN_PARENTHESIS && $parent->isParameterList()) { + $this->normaliseDeclarationList($items); + } + } + + /** + * Apply the rule to the given declarations + * + * Newlines are added between comma-delimited constant declarations and + * property declarations. When neither `StrictLists` nor `AlignLists` are + * enabled, they are also added to `use` statements between comma-delimited + * imports and trait insertions that break over multiple lines. + * + * If a list of property hooks has one or more attributes with a trailing + * newline, every attribute is placed on its own line, and blank lines are + * added before and after annotated hooks to improve readability. + */ + public function processDeclarations(array $declarations): void + { + foreach ($declarations as $token) { + $type = $token->Data[TokenData::NAMED_DECLARATION_TYPE]; + + if ( + $type === Type::_CONST + || $type === Type::PROPERTY + || $type & Type::_USE + ) { + $commas = $token->withNextSiblings($token->EndStatement) + ->getAnyOf(\T_COMMA); + if (!($type & Type::_USE) || ( + !$this->ListRuleEnabled + && $commas->tokenHasNewlineBeforeNextCode() + )) { + $commas->applyWhitespace(Space::LINE_AFTER); + } + } + + if ($type & Type::PROPERTY) { + /** @var TokenCollection */ + $hooks = $token->Data[TokenData::PROPERTY_HOOKS]; + if ($hooks->count()) { + $this->normaliseDeclarationList($hooks); + } + } + } + } + + /** + * @param iterable $items + */ + private function normaliseDeclarationList(iterable $items): void + { + $hasAttributeWithNewline = false; + foreach ($items as $item) { + $attributes = $item->withNextSiblingsFrom($this->Idx->Attribute, true); + $itemTokens[$item->index] = $attributes; + if ( + $attributes->tokenHasNewlineAfter(true) + || $attributes->shift()->tokenHasNewlineBefore() + ) { + $hasAttributeWithNewline = true; + break; + } + } + if (!$hasAttributeWithNewline) { + return; + } + + $addBlankBefore = false; + $i = 0; + foreach ($items as $item) { + if ($addBlankBefore) { + $item->applyBlankBefore(true); + $addBlankBefore = false; + $hasBlankBefore = true; + } else { + $hasBlankBefore = false; + } + $tokens = $itemTokens[$item->index] + ?? $item->withNextSiblingsFrom($this->Idx->Attribute, true); + $tokens[] = $item->skipNextSiblingFrom($this->Idx->Attribute); + foreach ($tokens as $token) { + $token->applyWhitespace(Space::LINE_BEFORE); + if ($this->Idx->Attribute[$token->id]) { + $token = $token->CloseBracket ?? $token; + $token->Whitespace |= Space::LINE_AFTER; + // Add a blank line before each item with an attribute, and + // another before the next item + $addBlankBefore = true; + } + } + if ($i++ && $addBlankBefore && !$hasBlankBefore) { + $item->applyBlankBefore(true); + } + } + } } diff --git a/tests/unit/Rule/ListSpacingTest.php b/tests/unit/Rule/ListSpacingTest.php deleted file mode 100644 index fa7a1e23..00000000 --- a/tests/unit/Rule/ListSpacingTest.php +++ /dev/null @@ -1,46 +0,0 @@ -assertCodeFormatIs($expected, $code); - } - - /** - * @return array - */ - public static function outputProvider(): array - { - return [ - [ - <<<'PHP' -tokenIndex(new TokenIndex(true)), ], + 'magic comma' => [ + <<<'PHP' + Date: Mon, 6 Jan 2025 23:58:52 +1100 Subject: [PATCH 04/21] Don't use `JSON_FORCE_OBJECT` when `--print-config` is given --- src/App/PrettyPHPCommand.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/App/PrettyPHPCommand.php b/src/App/PrettyPHPCommand.php index 20a53037..9bdb9578 100644 --- a/src/App/PrettyPHPCommand.php +++ b/src/App/PrettyPHPCommand.php @@ -976,11 +976,7 @@ protected function run(...$params) if ($this->PrintConfig) { $values = $this->getOptionValues(true, true, true); - echo Json::prettyPrint( - $values, - $values ? 0 : \JSON_FORCE_OBJECT - ) . \PHP_EOL; - + echo Json::prettyPrint((object) $values) . \PHP_EOL; return; } From c9d7de63ab9599ec07e2f46c99c822e49e9e6965 Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Tue, 7 Jan 2025 00:39:26 +1100 Subject: [PATCH 05/21] Clean up `TokenFlag` and `TokenData` - Rename for compactness: - `INFORMAL_DOC_COMMENT` -> `C_DOC_COMMENT` - `STATEMENT_TERMINATOR` -> `TERMINATOR` - `TERNARY_OPERATOR` -> `TERNARY` - `NAMED_DECLARATION` -> `DECLARATION` - `OTHER_TERNARY_OPERATOR` -> `OTHER_TERNARY` - `STRING_CLOSED_BY` -> `END_STRING` - `CHAIN_OPENED_BY` -> `CHAIN` - `NAMED_DECLARATION_PARTS` -> `DECLARATION_PARTS` - `NAMED_DECLARATION_TYPE` -> `DECLARATION_TYPE` --- docs/Flags.md | 8 ++-- src/Catalog/TokenData.php | 32 +++++++------ src/Catalog/TokenFlag.php | 19 ++++---- src/Contract/DeclarationRule.php | 4 +- src/Formatter.php | 8 ++-- src/Parser.php | 72 +++++++++++++++--------------- src/Renderer.php | 2 +- src/Rule/AlignChains.php | 2 +- src/Rule/AlignTernaryOperators.php | 6 +-- src/Rule/DeclarationSpacing.php | 4 +- src/Rule/HangingIndentation.php | 10 ++--- src/Rule/NormaliseComments.php | 4 +- src/Rule/NormaliseStrings.php | 6 +-- src/Rule/OperatorSpacing.php | 6 +-- src/Rule/PlaceBraces.php | 2 +- src/Rule/PlaceComments.php | 10 ++--- src/Rule/PreserveNewlines.php | 8 ++-- src/Rule/Preset/Symfony.php | 2 +- src/Rule/Preset/WordPress.php | 2 +- src/Rule/ProtectStrings.php | 2 +- src/Rule/StandardSpacing.php | 2 +- src/Rule/VerticalSpacing.php | 8 ++-- src/Token.php | 22 ++++----- src/TokenUtil.php | 28 ++++++------ tests/unit/ParserTest.php | 12 ++--- 25 files changed, 139 insertions(+), 142 deletions(-) diff --git a/docs/Flags.md b/docs/Flags.md index d36a4dab..d1062eca 100644 --- a/docs/Flags.md +++ b/docs/Flags.md @@ -12,14 +12,14 @@ | 1, 2 | 6 | `SHELL_COMMENT` ("#") | `Parser` | | 0, 3 | 9 | `C_COMMENT` ("/\*") | `Parser` | | 1, 3 | 10 | `DOC_COMMENT` ("/\*\*") | `Parser` | -| 4 | 16 | `INFORMAL_DOC_COMMENT` | `Parser` | +| 4 | 16 | `C_DOC_COMMENT` | `Parser` | | 5 | 32 | `COLLAPSIBLE_COMMENT` | `NormaliseComments` | | 6 | 64 | `CODE` | `Parser` | -| 7 | 128 | `STATEMENT_TERMINATOR` | `Parser` | +| 7 | 128 | `TERMINATOR` | `Parser` | | 8 | 256 | `STRUCTURAL_BRACE` | `Parser` | -| 9 | 512 | `TERNARY_OPERATOR` | `Parser` | +| 9 | 512 | `TERNARY` | `Parser` | | 10 | 1024 | `FN_DOUBLE_ARROW` | `Parser` | -| 11 | 2048 | `NAMED_DECLARATION` | `Parser` | +| 11 | 2048 | `DECLARATION` | `Parser` | | 12 | 4096 | `LIST_PARENT` | `Formatter` | | 13 | 8192 | `LIST_ITEM` | `Formatter` | | 14 | 16384 | `UNENCLOSED_PARENT` | `Parser` | diff --git a/src/Catalog/TokenData.php b/src/Catalog/TokenData.php index 3f1bdc80..44906958 100644 --- a/src/Catalog/TokenData.php +++ b/src/Catalog/TokenData.php @@ -10,8 +10,8 @@ interface TokenData { /** - * The content of a normalised T_COMMENT or T_DOC_COMMENT after removal of - * delimiters, trailing whitespace and leading asterisks + * The content of a normalised DocBlock token (T_DOC_COMMENT or T_COMMENT) + * after delimiters and trailing whitespace are removed */ public const COMMENT_CONTENT = 0; @@ -36,41 +36,39 @@ interface TokenData public const LIST_PARENT = 4; /** - * The T_COLON or T_QUESTION associated with a T_QUESTION or T_COLON flagged - * as a TERNARY_OPERATOR + * The other T_QUESTION or T_COLON associated with a TERNARY */ - public const OTHER_TERNARY_OPERATOR = 5; + public const OTHER_TERNARY = 5; /** * The last token of the string opened by the token */ - public const STRING_CLOSED_BY = 6; + public const END_STRING = 6; /** - * The first T_OBJECT_OPERATOR or T_NULLSAFE_OBJECT_OPERATOR in a chain - * thereof + * The first object operator in a chain of method calls */ - public const CHAIN_OPENED_BY = 7; + public const CHAIN = 7; /** - * A collection of tokens that form a NAMED_DECLARATION + * A collection of tokens that form a DECLARATION */ - public const NAMED_DECLARATION_PARTS = 8; + public const DECLARATION_PARTS = 8; /** - * The type of a NAMED_DECLARATION + * The type of a DECLARATION */ - public const NAMED_DECLARATION_TYPE = 9; + public const DECLARATION_TYPE = 9; /** - * A collection of property hooks for a NAMED_DECLARATION with type PROPERTY - * or PROMOTED_PARAM + * A collection of property hooks associated with a DECLARATION of type + * PROPERTY or PROMOTED_PARAM */ public const PROPERTY_HOOKS = 10; /** - * A list of closures that align other tokens with the token when its output - * column changes + * An array of closures that align other tokens with the token when its + * output column changes */ public const ALIGNMENT_CALLBACKS = 11; diff --git a/src/Catalog/TokenFlag.php b/src/Catalog/TokenFlag.php index 46975a81..eae3d6ba 100644 --- a/src/Catalog/TokenFlag.php +++ b/src/Catalog/TokenFlag.php @@ -43,7 +43,7 @@ interface TokenFlag * The token is a C-style comment where every line starts with "*" or at * least one delimiter appears on its own line */ - public const INFORMAL_DOC_COMMENT = 16; + public const C_DOC_COMMENT = 16; /** * The token is a collapsible one-line T_DOC_COMMENT @@ -56,13 +56,12 @@ interface TokenFlag public const CODE = 64; /** - * The token is a T_CLOSE_BRACE or T_CLOSE_TAG that terminates a statement + * The token is a T_CLOSE_BRACE or T_CLOSE_TAG at the end of a statement */ - public const STATEMENT_TERMINATOR = 128; + public const TERMINATOR = 128; /** - * The token is a T_OPEN_BRACE or T_CLOSE_BRACE that delimits a code block - * or trait adaptation + * The token is a brace that delimits a code block or trait adaptation * * Not applied to braces in: * @@ -73,19 +72,19 @@ interface TokenFlag public const STRUCTURAL_BRACE = 256; /** - * The token is a T_QUESTION or T_COLON belonging to a ternary operator + * The token is a T_QUESTION or T_COLON in a ternary expression */ - public const TERNARY_OPERATOR = 512; + public const TERNARY = 512; /** - * The token is a T_DOUBLE_ARROW belonging to an arrow function + * The token is a T_DOUBLE_ARROW in an arrow function */ public const FN_DOUBLE_ARROW = 1024; /** - * The token is the first in a statement that declares a named entity + * The token is the first in a non-anonymous declaration */ - public const NAMED_DECLARATION = 2048; + public const DECLARATION = 2048; /** * The token is the parent of a list of items diff --git a/src/Contract/DeclarationRule.php b/src/Contract/DeclarationRule.php index 1f5b814d..05025f09 100644 --- a/src/Contract/DeclarationRule.php +++ b/src/Contract/DeclarationRule.php @@ -38,8 +38,8 @@ public static function needsSortedDeclarations(): bool; * document. The following values are applied to each token's * {@see Token::$Data} array: * - * - {@see TokenData::NAMED_DECLARATION_PARTS} - * - {@see TokenData::NAMED_DECLARATION_TYPE} + * - {@see TokenData::DECLARATION_PARTS} + * - {@see TokenData::DECLARATION_TYPE} * - {@see TokenData::PROPERTY_HOOKS} (if the declaration is a property or * promoted constructor parameter) * diff --git a/src/Formatter.php b/src/Formatter.php index 1b5a468c..76803fdd 100644 --- a/src/Formatter.php +++ b/src/Formatter.php @@ -980,7 +980,7 @@ public function format( case \T_STATIC: if ( $parent->Statement !== $parent - || $parent->Flags & TokenFlag::NAMED_DECLARATION + || $parent->Flags & TokenFlag::DECLARATION ) { continue 2; } @@ -1032,8 +1032,8 @@ public function format( /** @var Token */ $statement = $parent->Statement; if (!( - $statement->Flags & TokenFlag::NAMED_DECLARATION - && ($statement->Data[TokenData::NAMED_DECLARATION_TYPE] & ( + $statement->Flags & TokenFlag::DECLARATION + && ($statement->Data[TokenData::DECLARATION_TYPE] & ( Type::_USE | Type::_TRAIT )) === Type::_USE @@ -1081,7 +1081,7 @@ public function format( Type::USE_TRAIT => true, ]); foreach ($parents as $i => $parent) { - $type = $parent->Data[TokenData::NAMED_DECLARATION_TYPE]; + $type = $parent->Data[TokenData::DECLARATION_TYPE]; $first = null; $last = null; diff --git a/src/Parser.php b/src/Parser.php index e826b644..d2acae11 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -152,7 +152,7 @@ private function linkTokens(array $tokens): void * - `Depth` * - `String` * - `Heredoc` - * - `Data[TokenData::STRING_CLOSED_BY]` + * - `Data[TokenData::END_STRING]` * * @param non-empty-list $tokens * @param-out non-empty-list $tokens @@ -318,7 +318,7 @@ private function buildHierarchy( ) && ( $prevCode->id === \T_SEMICOLON || ( - $prevCode->Flags & TokenFlag::STATEMENT_TERMINATOR && !( + $prevCode->Flags & TokenFlag::TERMINATOR && !( $prevCode->id === \T_CLOSE_BRACE && $this->continuesEnclosed($trigger, $prevCode) ) @@ -424,7 +424,7 @@ private function buildHierarchy( || !Regex::match('/\S((?Flags |= TokenFlag::INFORMAL_DOC_COMMENT; + $token->Flags |= TokenFlag::C_DOC_COMMENT; } } @@ -438,11 +438,11 @@ private function buildHierarchy( && $t->id !== \T_OPEN_BRACE && ( $t->id !== \T_CLOSE_BRACE - || !($t->Flags & TokenFlag::STATEMENT_TERMINATOR) + || !($t->Flags & TokenFlag::TERMINATOR) ) ) { $token->Flags |= TokenFlag::CODE - | TokenFlag::STATEMENT_TERMINATOR; + | TokenFlag::TERMINATOR; } } elseif (!$idx->NotCode[$token->id]) { $token->Flags |= TokenFlag::CODE; @@ -484,8 +484,8 @@ private function buildHierarchy( if ($idx->StringDelimiter[$prev->id]) { if ( $prev->String - && isset($prev->String->Data[TokenData::STRING_CLOSED_BY]) - && $prev->String->Data[TokenData::STRING_CLOSED_BY] === $prev + && isset($prev->String->Data[TokenData::END_STRING]) + && $prev->String->Data[TokenData::END_STRING] === $prev ) { $token->String = $prev->String->String; if ($prev->id === \T_END_HEREDOC) { @@ -509,7 +509,7 @@ private function buildHierarchy( || ($token->String->id !== \T_START_HEREDOC && $token->String->id === $token->id) ) ) { - $token->String->Data[TokenData::STRING_CLOSED_BY] = $token; + $token->String->Data[TokenData::END_STRING] = $token; } if ($idx->CloseBracketOrVirtual[$token->id]) { @@ -558,7 +558,7 @@ private function buildHierarchy( break; } - $token->Flags |= TokenFlag::STATEMENT_TERMINATOR; + $token->Flags |= TokenFlag::TERMINATOR; $prev = $token; continue; @@ -648,8 +648,8 @@ private function parseStatements(array $scopes, ?array &$statements): void // The following tokens are regarded as statement terminators: // // - `T_SEMICOLON`, or `T_CLOSE_BRACE` / `T_CLOSE_TAG` where the - // `STATEMENT_TERMINATOR` flag is set, unless the next token - // continues an open control structure + // `TERMINATOR` flag is set, unless the next token continues + // an open control structure // - `T_COLON` after a switch case or a label // - `T_COMMA`: // - between parentheses and square brackets, e.g. in argument @@ -661,12 +661,12 @@ private function parseStatements(array $scopes, ?array &$statements): void if ( !$token->NextSibling || $token->id === \T_SEMICOLON - || $token->Flags & TokenFlag::STATEMENT_TERMINATOR + || $token->Flags & TokenFlag::TERMINATOR || ( ($close = $token->CloseBracket) && ( $close->id === \T_CLOSE_UNENCLOSED - || $close->Flags & TokenFlag::STATEMENT_TERMINATOR + || $close->Flags & TokenFlag::TERMINATOR ) && ( !($next = $close->NextCode) || !( @@ -722,11 +722,11 @@ private function parseStatements(array $scopes, ?array &$statements): void * * Token properties set: * - * - `Data[TokenData::NAMED_DECLARATION_PARTS]` - * - `Data[TokenData::NAMED_DECLARATION_TYPE]` + * - `Data[TokenData::DECLARATION_PARTS]` + * - `Data[TokenData::DECLARATION_TYPE]` * - `Data[TokenData::PROPERTY_HOOKS]` - * - `Data[TokenData::OTHER_TERNARY_OPERATOR]` - * - `Data[TokenData::CHAIN_OPENED_BY]` + * - `Data[TokenData::OTHER_TERNARY]` + * - `Data[TokenData::CHAIN]` * * @param Token[] $statements * @param array|null $declarations @@ -793,9 +793,9 @@ private function parseExpressions( $type = Type::USE_TRAIT; } if ($type) { - $statement->Flags |= TokenFlag::NAMED_DECLARATION; - $statement->Data[TokenData::NAMED_DECLARATION_PARTS] = $parts; - $statement->Data[TokenData::NAMED_DECLARATION_TYPE] = $type; + $statement->Flags |= TokenFlag::DECLARATION; + $statement->Data[TokenData::DECLARATION_PARTS] = $parts; + $statement->Data[TokenData::DECLARATION_TYPE] = $type; $declarations[$statement->index] = $statement; $declarationsByType[$type][$statement->index] = $statement; @@ -814,9 +814,9 @@ private function parseExpressions( } while ($current = $current->NextSibling); } foreach ($hooks as $hook) { - $hook->Flags |= TokenFlag::NAMED_DECLARATION; - $hook->Data[TokenData::NAMED_DECLARATION_PARTS] = $hook->namedDeclarationParts(); - $hook->Data[TokenData::NAMED_DECLARATION_TYPE] = Type::HOOK; + $hook->Flags |= TokenFlag::DECLARATION; + $hook->Data[TokenData::DECLARATION_PARTS] = $hook->namedDeclarationParts(); + $hook->Data[TokenData::DECLARATION_TYPE] = Type::HOOK; $declarations[$hook->index] = $hook; $declarationsByType[Type::HOOK][$hook->index] = $hook; } @@ -856,24 +856,24 @@ private function parseExpressions( } else { continue; } - $current->Flags |= TokenFlag::TERNARY_OPERATOR; - $token->Flags |= TokenFlag::TERNARY_OPERATOR; - $current->Data[TokenData::OTHER_TERNARY_OPERATOR] = $token; - $token->Data[TokenData::OTHER_TERNARY_OPERATOR] = $current; + $current->Flags |= TokenFlag::TERNARY; + $token->Flags |= TokenFlag::TERNARY; + $current->Data[TokenData::OTHER_TERNARY] = $token; + $token->Data[TokenData::OTHER_TERNARY] = $current; break; } } // Link chained object operators - if ($idx->Chain[$token->id] && !isset($token->Data[TokenData::CHAIN_OPENED_BY])) { - $token->Data[TokenData::CHAIN_OPENED_BY] = $token; + if ($idx->Chain[$token->id] && !isset($token->Data[TokenData::CHAIN])) { + $token->Data[TokenData::CHAIN] = $token; $current = $token; while ( ($current = $current->NextSibling) && $idx->ChainPart[$current->id] ) { if ($idx->Chain[$current->id]) { - $current->Data[TokenData::CHAIN_OPENED_BY] = $token; + $current->Data[TokenData::CHAIN] = $token; } } } @@ -958,12 +958,12 @@ private function isStructuralBrace(Token $token): bool // Braces cannot be empty in dereferencing contexts, but they can be in // property hooks and trait adaptations - return $t === $token // `{}` - || $t->id === \T_SEMICOLON // `{ statement; }` - || $t->id === \T_COLON // `{ label: }` - || ($t->Flags & TokenFlag::STATEMENT_TERMINATOR) /* `{ statement ?>...id === \T_CLOSE_UNENCLOSED // `{ if (...) statement; }` - || ( // `{ { statement; } }` + return $t === $token // `{}` + || $t->id === \T_SEMICOLON // `{ statement; }` + || $t->id === \T_COLON // `{ label: }` + || ($t->Flags & TokenFlag::TERMINATOR) /* `{ statement ?>...id === \T_CLOSE_UNENCLOSED // `{ if (...) statement; }` + || ( // `{ { statement; } }` $t->id === \T_CLOSE_BRACE && $t->OpenBracket && $t->OpenBracket->id === \T_OPEN_BRACE diff --git a/src/Renderer.php b/src/Renderer.php index 529851a7..c1e12b13 100644 --- a/src/Renderer.php +++ b/src/Renderer.php @@ -304,7 +304,7 @@ private function getMultiLineComment(Token $token, bool $softTabs): string // alignment if possible if ( $token->id === \T_COMMENT - && !($token->Flags & TokenFlag::INFORMAL_DOC_COMMENT) + && !($token->Flags & TokenFlag::C_DOC_COMMENT) ) { $text = $token->expandText(true); $delta = $token->OutputColumn - $token->column; diff --git a/src/Rule/AlignChains.php b/src/Rule/AlignChains.php index fe00f002..4652ea75 100644 --- a/src/Rule/AlignChains.php +++ b/src/Rule/AlignChains.php @@ -79,7 +79,7 @@ public static function needsSortedTokens(): bool public function processTokens(array $tokens): void { foreach ($tokens as $token) { - if ($token !== $token->Data[TokenData::CHAIN_OPENED_BY]) { + if ($token !== $token->Data[TokenData::CHAIN]) { continue; } diff --git a/src/Rule/AlignTernaryOperators.php b/src/Rule/AlignTernaryOperators.php index 676e7476..c5e49109 100644 --- a/src/Rule/AlignTernaryOperators.php +++ b/src/Rule/AlignTernaryOperators.php @@ -74,7 +74,7 @@ public function processTokens(array $tokens): void // start of a line if (( $token->id === \T_QUESTION - && !($token->Flags & TokenFlag::TERNARY_OPERATOR) + && !($token->Flags & TokenFlag::TERNARY) ) || !$token->hasNewlineBefore()) { continue; } @@ -129,8 +129,8 @@ static function () use ($token, $alignWith, $until, $tabSize) { private function setAlignedWith(Token $token, Token $alignWith): void { $token->AlignedWith = $alignWith; - if ($token->Flags & TokenFlag::TERNARY_OPERATOR) { - $other = $token->Data[TokenData::OTHER_TERNARY_OPERATOR]; + if ($token->Flags & TokenFlag::TERNARY) { + $other = $token->Data[TokenData::OTHER_TERNARY]; if ($other->hasNewlineBefore()) { $other->AlignedWith = $alignWith; } diff --git a/src/Rule/DeclarationSpacing.php b/src/Rule/DeclarationSpacing.php index a9ae2503..24a7d8b2 100644 --- a/src/Rule/DeclarationSpacing.php +++ b/src/Rule/DeclarationSpacing.php @@ -97,9 +97,9 @@ public function processDeclarations(array $declarations): void $declDepths = []; foreach ($declarations as $token) { - $type = $token->Data[TokenData::NAMED_DECLARATION_TYPE]; + $type = $token->Data[TokenData::DECLARATION_TYPE]; /** @var TokenCollection */ - $parts = $token->Data[TokenData::NAMED_DECLARATION_PARTS]; + $parts = $token->Data[TokenData::DECLARATION_PARTS]; // Don't separate `use`, `use function` and `use constant` if // imports are not being sorted diff --git a/src/Rule/HangingIndentation.php b/src/Rule/HangingIndentation.php index aa16731d..478dd359 100644 --- a/src/Rule/HangingIndentation.php +++ b/src/Rule/HangingIndentation.php @@ -151,8 +151,8 @@ public function processTokens(array $tokens): void $prevSibling = $token->PrevSibling; /** @var Token */ $statement = $token->Statement; - $declType = $statement->Flags & TokenFlag::NAMED_DECLARATION - ? $statement->Data[TokenData::NAMED_DECLARATION_TYPE] + $declType = $statement->Flags & TokenFlag::DECLARATION + ? $statement->Data[TokenData::DECLARATION_TYPE] : 0; $mayHaveListWithEqual = $declType === Type::_CONST || $declType === Type::PROPERTY @@ -326,10 +326,10 @@ public function processTokens(array $tokens): void $firstItem = $listItems->first(); $context[] = $firstItem; } elseif ($this->Idx->Chain[$token->id]) { - $context[] = $token->Data[TokenData::CHAIN_OPENED_BY]; + $context[] = $token->Data[TokenData::CHAIN]; $until = TokenUtil::getOperatorEndExpression($token); } elseif ( - $token->Flags & TokenFlag::TERNARY_OPERATOR + $token->Flags & TokenFlag::TERNARY || $token->id === \T_COALESCE ) { $ternary = TokenUtil::getTernaryContext($token) @@ -420,7 +420,7 @@ public function processTokens(array $tokens): void ($next = $until->NextCode) && (( $next->id === \T_QUESTION - && $next->Flags & TokenFlag::TERNARY_OPERATOR + && $next->Flags & TokenFlag::TERNARY ) || $next->id === \T_COALESCE) && !TokenUtil::getTernaryContext($next) ) { diff --git a/src/Rule/NormaliseComments.php b/src/Rule/NormaliseComments.php index 65cfd3ba..7f1f2a1f 100644 --- a/src/Rule/NormaliseComments.php +++ b/src/Rule/NormaliseComments.php @@ -89,7 +89,7 @@ public function processTokens(array $tokens): void if ( $type === TokenFlag::C_COMMENT - && !($token->Flags & TokenFlag::INFORMAL_DOC_COMMENT) + && !($token->Flags & TokenFlag::C_DOC_COMMENT) ) { if ($token->hasNewline()) { continue; @@ -228,7 +228,7 @@ public function processTokens(array $tokens): void || $next->getSubId() !== TokenSubId::USE_IMPORT ) )) { - if (!($next && $next->Flags & TokenFlag::NAMED_DECLARATION) || ( + if (!($next && $next->Flags & TokenFlag::DECLARATION) || ( $next->id === \T_USE && $next->getSubId() === TokenSubId::USE_TRAIT )) { diff --git a/src/Rule/NormaliseStrings.php b/src/Rule/NormaliseStrings.php index 0fb7b091..cc20add1 100644 --- a/src/Rule/NormaliseStrings.php +++ b/src/Rule/NormaliseStrings.php @@ -130,7 +130,7 @@ public function processTokens(array $tokens): void break; case \T_START_HEREDOC: - $closedBy = $openedBy->Data[TokenData::STRING_CLOSED_BY]; + $closedBy = $openedBy->Data[TokenData::END_STRING]; $start = trim($openedBy->text); $text = $token->text; $end = trim($closedBy->text); @@ -208,7 +208,7 @@ function ($matches) use (&$utf8Escapes) { $reserved = "[nrtvef\\\\\${$reserved}]|[0-7]|x[0-9a-fA-F]|u\{[0-9a-fA-F]+\}"; if ( $token->id === \T_CONSTANT_ENCAPSED_STRING - || $next !== $openedBy->Data[TokenData::STRING_CLOSED_BY] + || $next !== $openedBy->Data[TokenData::END_STRING] || $openedBy->id !== \T_START_HEREDOC ) { $reserved .= '|$'; @@ -223,7 +223,7 @@ function ($matches) use (&$utf8Escapes) { // the brace to remain escaped lest it become a `T_CURLY_OPEN` if ( $token->id !== \T_CONSTANT_ENCAPSED_STRING - && $next !== $openedBy->Data[TokenData::STRING_CLOSED_BY] + && $next !== $openedBy->Data[TokenData::END_STRING] ) { $double = Regex::replace( '/(?Whitespace |= Space::NONE_BEFORE | Space::NONE_AFTER; } elseif ( $token->id === \T_QUESTION - && !($token->Flags & TokenFlag::TERNARY_OPERATOR) + && !($token->Flags & TokenFlag::TERNARY) ) { $token->Whitespace |= Space::SPACE_BEFORE | Space::NONE_AFTER; } elseif ( @@ -172,8 +172,8 @@ public function processTokens(array $tokens): void $token->Whitespace |= Space::NONE_AFTER; } elseif ($token->id === \T_COLON) { $token->Whitespace |= ( - $token->Flags & TokenFlag::TERNARY_OPERATOR - ? ($token->Data[TokenData::OTHER_TERNARY_OPERATOR] === $prev + $token->Flags & TokenFlag::TERNARY + ? ($token->Data[TokenData::OTHER_TERNARY] === $prev ? Space::NONE_BEFORE : Space::SPACE_BEFORE) : 0 diff --git a/src/Rule/PlaceBraces.php b/src/Rule/PlaceBraces.php index ba87a9ac..64ac6aea 100644 --- a/src/Rule/PlaceBraces.php +++ b/src/Rule/PlaceBraces.php @@ -95,7 +95,7 @@ public function processTokens(array $tokens): void // Don't move subsequent code to the next line if the brace is part // of an expression - if ($close->Flags & TokenFlag::STATEMENT_TERMINATOR) { + if ($close->Flags & TokenFlag::TERMINATOR) { // Keep structures like `} else {` on the same line $next = $close->NextCode; if ($next && $next->continuesControlStructure()) { diff --git a/src/Rule/PlaceComments.php b/src/Rule/PlaceComments.php index ea4c5892..cd11d2b6 100644 --- a/src/Rule/PlaceComments.php +++ b/src/Rule/PlaceComments.php @@ -114,8 +114,8 @@ public function processTokens(array $tokens): void && $prev->id === \T_CLOSE_BRACE && $prev->Flags & TokenFlag::STRUCTURAL_BRACE && $prev->Statement - && $prev->Statement->Flags & TokenFlag::NAMED_DECLARATION - && $prev->Statement->Data[TokenData::NAMED_DECLARATION_TYPE] & ( + && $prev->Statement->Flags & TokenFlag::DECLARATION + && $prev->Statement->Data[TokenData::DECLARATION_TYPE] & ( DeclarationType::_CLASS | DeclarationType::_ENUM | DeclarationType::_INTERFACE @@ -154,7 +154,7 @@ public function processTokens(array $tokens): void if ( $token->id !== \T_DOC_COMMENT - && !($token->Flags & TokenFlag::INFORMAL_DOC_COMMENT) + && !($token->Flags & TokenFlag::C_DOC_COMMENT) ) { continue; } @@ -173,8 +173,8 @@ public function processTokens(array $tokens): void if ( $next - && $next->Flags & TokenFlag::NAMED_DECLARATION - && ($type = $next->Data[TokenData::NAMED_DECLARATION_TYPE]) & ( + && $next->Flags & TokenFlag::DECLARATION + && ($type = $next->Data[TokenData::DECLARATION_TYPE]) & ( DeclarationType::_DECLARE | DeclarationType::_NAMESPACE | DeclarationType::_USE diff --git a/src/Rule/PreserveNewlines.php b/src/Rule/PreserveNewlines.php index a0fb9bb3..fb15cd21 100644 --- a/src/Rule/PreserveNewlines.php +++ b/src/Rule/PreserveNewlines.php @@ -155,9 +155,9 @@ private function maybePreserveNewlineBefore( // Treat `?:` as one operator if ( - ($token->Flags & TokenFlag::TERNARY_OPERATOR) + ($token->Flags & TokenFlag::TERNARY) && $token->id === \T_COLON - && $token->Data[TokenData::OTHER_TERNARY_OPERATOR] === $prev + && $token->Data[TokenData::OTHER_TERNARY] === $prev ) { return false; } @@ -199,9 +199,9 @@ private function maybePreserveNewlineAfter( // Treat `?:` as one operator if ( - ($token->Flags & TokenFlag::TERNARY_OPERATOR) + ($token->Flags & TokenFlag::TERNARY) && $token->id === \T_QUESTION - && $token->Data[TokenData::OTHER_TERNARY_OPERATOR] === $next + && $token->Data[TokenData::OTHER_TERNARY] === $next ) { return false; } diff --git a/src/Rule/Preset/Symfony.php b/src/Rule/Preset/Symfony.php index 7c042050..f65420f5 100644 --- a/src/Rule/Preset/Symfony.php +++ b/src/Rule/Preset/Symfony.php @@ -107,7 +107,7 @@ public function processList(Token $parent, TokenCollection $items, Token $lastCh } foreach ($items as $item) { - if ($item->Flags & TokenFlag::NAMED_DECLARATION) { + if ($item->Flags & TokenFlag::DECLARATION) { return; } } diff --git a/src/Rule/Preset/WordPress.php b/src/Rule/Preset/WordPress.php index 76973ffd..890fd683 100644 --- a/src/Rule/Preset/WordPress.php +++ b/src/Rule/Preset/WordPress.php @@ -113,7 +113,7 @@ public function processTokens(array $tokens): void foreach ($tokens as $token) { if ( $token->id === \T_COMMENT - && !($token->Flags & TokenFlag::INFORMAL_DOC_COMMENT) + && !($token->Flags & TokenFlag::C_DOC_COMMENT) ) { continue; } diff --git a/src/Rule/ProtectStrings.php b/src/Rule/ProtectStrings.php index 70af24b2..762e83fa 100644 --- a/src/Rule/ProtectStrings.php +++ b/src/Rule/ProtectStrings.php @@ -65,7 +65,7 @@ public function processTokens(array $tokens): void continue; } - $closedBy = $token->Data[TokenData::STRING_CLOSED_BY]; + $closedBy = $token->Data[TokenData::END_STRING]; foreach ($next->withNextSiblings($closedBy) as $current) { $current->Whitespace |= Space::CRITICAL_NONE_BEFORE; if ($current->id === \T_OPEN_BRACKET) { diff --git a/src/Rule/StandardSpacing.php b/src/Rule/StandardSpacing.php index 16924caf..19a8d9d6 100644 --- a/src/Rule/StandardSpacing.php +++ b/src/Rule/StandardSpacing.php @@ -350,7 +350,7 @@ public function processDeclarations(array $declarations): void { $parents = []; foreach ($declarations as $token) { - $type = $token->Data[TokenData::NAMED_DECLARATION_TYPE]; + $type = $token->Data[TokenData::DECLARATION_TYPE]; // Collect promoted constructor parameters if ($type === DeclarationType::PARAM) { diff --git a/src/Rule/VerticalSpacing.php b/src/Rule/VerticalSpacing.php index 9b1c2df2..3fe4ee05 100644 --- a/src/Rule/VerticalSpacing.php +++ b/src/Rule/VerticalSpacing.php @@ -343,11 +343,11 @@ public function processTokens(array $tokens): void $token->Whitespace |= Space::LINE_BEFORE; } elseif ($token->id === \T_QUESTION) { - if (!($token->Flags & TokenFlag::TERNARY_OPERATOR)) { + if (!($token->Flags & TokenFlag::TERNARY)) { continue; } - $other = $token->Data[TokenData::OTHER_TERNARY_OPERATOR]; + $other = $token->Data[TokenData::OTHER_TERNARY]; if ($other === $token->Next) { continue; } @@ -360,7 +360,7 @@ public function processTokens(array $tokens): void $token->Whitespace |= Space::LINE_BEFORE; } } else { - if ($token !== $token->Data[TokenData::CHAIN_OPENED_BY]) { + if ($token !== $token->Data[TokenData::CHAIN]) { continue; } @@ -440,7 +440,7 @@ public function processList(Token $parent, TokenCollection $items, Token $lastCh public function processDeclarations(array $declarations): void { foreach ($declarations as $token) { - $type = $token->Data[TokenData::NAMED_DECLARATION_TYPE]; + $type = $token->Data[TokenData::DECLARATION_TYPE]; if ( $type === Type::_CONST diff --git a/src/Token.php b/src/Token.php index 39d7cec8..abbbb83f 100644 --- a/src/Token.php +++ b/src/Token.php @@ -623,10 +623,10 @@ private function getColonSubId(): int if ($prevCode->id === \T_STRING && ( !($prev = $prevCode->PrevSibling) || ( $prev->id === \T_SEMICOLON - || $prev->Flags & TokenFlag::STATEMENT_TERMINATOR + || $prev->Flags & TokenFlag::TERMINATOR || ( $prev->CloseBracket - && $prev->CloseBracket->Flags & TokenFlag::STATEMENT_TERMINATOR + && $prev->CloseBracket->Flags & TokenFlag::TERMINATOR ) || $this->Idx->HasOptionalBraces[$prev->id] || ( @@ -680,7 +680,7 @@ private function getQuestionSubId(): int // Nullable variable types (and constant types, as of PHP 8.3) ( $this->Idx->NonMethodMember[$prevCode->id] - && $statement->Flags & TokenFlag::NAMED_DECLARATION + && $statement->Flags & TokenFlag::DECLARATION ) // Nullable return types || ($prevCode->id === \T_COLON && $prevCode->isColonTypeDelimiter()) @@ -703,8 +703,8 @@ private function getUseSubId(): int } if ( - $this->Flags & TokenFlag::NAMED_DECLARATION - && $this->Data[TokenData::NAMED_DECLARATION_TYPE] === DeclarationType::USE_TRAIT + $this->Flags & TokenFlag::DECLARATION + && $this->Data[TokenData::DECLARATION_TYPE] === DeclarationType::USE_TRAIT ) { return TokenSubId::USE_TRAIT; } @@ -744,7 +744,7 @@ public function inUnaryContext(): bool return $this->Statement === $this || !($prev = $this->PrevCode) || $this->Idx->BeforeUnary[$prev->id] - || $prev->Flags & TokenFlag::TERNARY_OPERATOR; + || $prev->Flags & TokenFlag::TERNARY; } /** @@ -941,8 +941,8 @@ public function inPropertyHook(): bool */ public function isProperty(): bool { - return $this->Flags & TokenFlag::NAMED_DECLARATION - && $this->Data[TokenData::NAMED_DECLARATION_TYPE] & DeclarationType::PROPERTY; + return $this->Flags & TokenFlag::DECLARATION + && $this->Data[TokenData::DECLARATION_TYPE] & DeclarationType::PROPERTY; } /** @@ -980,7 +980,7 @@ public function inAnonymousFunctionOrFn(): bool private function isAnonymousFunctionOrFn(): bool { - return !($this->Flags & TokenFlag::NAMED_DECLARATION) + return !($this->Flags & TokenFlag::DECLARATION) && $this->Idx->FunctionOrFn[$this->skipNextSiblingFrom($this->Idx->AttributeOrStatic)->id]; } @@ -995,7 +995,7 @@ public function inDeclaration(): bool private function isDeclaration(): bool { - return $this->Flags & TokenFlag::NAMED_DECLARATION + return $this->Flags & TokenFlag::DECLARATION || $this->Idx->ClassOrFunction[ $this->skipNextSiblingFrom($this->Idx->BeforeAnonymousClassOrFunction)->id ]; @@ -1009,7 +1009,7 @@ public function skipToStartOfDeclaration(): self { if ( $this->Idx->ExpressionDelimiter[$this->id] - || $this->Flags & TokenFlag::TERNARY_OPERATOR + || $this->Flags & TokenFlag::TERNARY ) { // @codeCoverageIgnoreStart return $this; diff --git a/src/TokenUtil.php b/src/TokenUtil.php index 4b2e1a7c..9f2a1f9e 100644 --- a/src/TokenUtil.php +++ b/src/TokenUtil.php @@ -40,7 +40,7 @@ public static function isNewlineAllowedBefore(Token $token): bool } // Don't allow newlines before `:` other than ternary operators - if ($token->id === \T_COLON && !($token->Flags & TokenFlag::TERNARY_OPERATOR)) { + if ($token->id === \T_COLON && !($token->Flags & TokenFlag::TERNARY)) { return false; } @@ -208,7 +208,7 @@ public static function getOperatorPrecedence( $arity === 0 || ($arity === self::UNARY && $token->inUnaryContext()) || ($arity === self::BINARY && !$token->inUnaryContext()) - || ($arity === self::TERNARY && $token->Flags & TokenFlag::TERNARY_OPERATOR) + || ($arity === self::TERNARY && $token->Flags & TokenFlag::TERNARY) ) { $leftAssociative = $leftAssoc; $rightAssociative = $rightAssoc; @@ -271,7 +271,7 @@ public static function getPrecedenceOf( public static function getTernaryContext(Token $token): ?Token { $precedence = self::getPrecedenceOf(\T_QUESTION, false, true); - if ($ternary = $token->Flags & TokenFlag::TERNARY_OPERATOR) { + if ($ternary = $token->Flags & TokenFlag::TERNARY) { /** @var Token */ $before = self::getTernary1($token); $short = $before->NextCode === self::getTernary2($token); @@ -288,10 +288,10 @@ public static function getTernaryContext(Token $token): ?Token ) { if ($t->id === \T_COALESCE) { $context = $t; - } elseif ($t->Flags & TokenFlag::TERNARY_OPERATOR) { + } elseif ($t->Flags & TokenFlag::TERNARY) { if ( self::getTernary1($t) === $t - && $t->Data[TokenData::OTHER_TERNARY_OPERATOR]->index + && $t->Data[TokenData::OTHER_TERNARY]->index < $before->index ) { $context = $t; @@ -325,7 +325,7 @@ public static function getTernaryExpression(Token $context): Token && $prev->Statement === $context->Statement && $prev->id !== \T_COMMA ) { - if ($prev->Flags & TokenFlag::TERNARY_OPERATOR) { + if ($prev->Flags & TokenFlag::TERNARY) { return $t; } if (self::OPERATOR_PRECEDENCE_INDEX[$prev->id]) { @@ -356,11 +356,11 @@ public static function getTernaryEndExpression(Token $token): Token || !$token->Idx->StatementDelimiter[$next->id] ) ) { - if ($next->Flags & TokenFlag::TERNARY_OPERATOR) { + if ($next->Flags & TokenFlag::TERNARY) { if ($next->id === \T_COLON) { return $t->CloseBracket ?? $t; } - $next = $next->Data[TokenData::OTHER_TERNARY_OPERATOR]; + $next = $next->Data[TokenData::OTHER_TERNARY]; } elseif (self::OPERATOR_PRECEDENCE_INDEX[$next->id]) { $nextPrecedence = self::getOperatorPrecedence($next); if ($nextPrecedence !== -1 && $nextPrecedence < 99 && $nextPrecedence > $precedence) { @@ -378,10 +378,10 @@ public static function getTernaryEndExpression(Token $token): Token */ public static function getTernary1(Token $token): ?Token { - return $token->Flags & TokenFlag::TERNARY_OPERATOR + return $token->Flags & TokenFlag::TERNARY ? ($token->id === \T_QUESTION ? $token - : $token->Data[TokenData::OTHER_TERNARY_OPERATOR]) + : $token->Data[TokenData::OTHER_TERNARY]) : null; } @@ -391,10 +391,10 @@ public static function getTernary1(Token $token): ?Token */ public static function getTernary2(Token $token): ?Token { - return $token->Flags & TokenFlag::TERNARY_OPERATOR + return $token->Flags & TokenFlag::TERNARY ? ($token->id === \T_COLON ? $token - : $token->Data[TokenData::OTHER_TERNARY_OPERATOR]) + : $token->Data[TokenData::OTHER_TERNARY]) : null; } @@ -411,8 +411,8 @@ public static function getTernary2AfterTernary1(Token $token): ?Token if ($t->id === \T_NULL) { return null; } - } while (!($t->Flags & TokenFlag::TERNARY_OPERATOR)); - $other = $t->Data[TokenData::OTHER_TERNARY_OPERATOR]; + } while (!($t->Flags & TokenFlag::TERNARY)); + $other = $t->Data[TokenData::OTHER_TERNARY]; return $other->index > $token->index ? $other : null; diff --git a/tests/unit/ParserTest.php b/tests/unit/ParserTest.php index d85d4250..184a8f1d 100644 --- a/tests/unit/ParserTest.php +++ b/tests/unit/ParserTest.php @@ -223,7 +223,7 @@ public static function parseProvider(): array 'pos' => 52, 'PrevSibling' => "T15:L5:'endif'", 'Parent' => "T5:L2:')'<<(virtual)", - 'Flags' => 'CODE|STATEMENT_TERMINATOR', + 'Flags' => 'CODE|TERMINATOR', ], [ 'id' => 'T_OPEN_TAG', @@ -293,7 +293,7 @@ public static function parseProvider(): array 'line' => 8, 'pos' => 65, 'PrevSibling' => "T20:L7:'else'<<(virtual)", - 'Flags' => 'CODE|STATEMENT_TERMINATOR', + 'Flags' => 'CODE|TERMINATOR', ], [ 'id' => 'T_OPEN_TAG', @@ -533,7 +533,7 @@ public static function parseProvider(): array 'pos' => 112, 'PrevSibling' => "T19:L5:'endif'", 'Parent' => "T6:L2:')'<<(virtual)", - 'Flags' => 'CODE|STATEMENT_TERMINATOR', + 'Flags' => 'CODE|TERMINATOR', ], [ 'id' => 'T_OPEN_TAG', @@ -620,7 +620,7 @@ public static function parseProvider(): array 'line' => 8, 'pos' => 149, 'PrevSibling' => "T26:L7:'else'<<(virtual)", - 'Flags' => 'CODE|STATEMENT_TERMINATOR', + 'Flags' => 'CODE|TERMINATOR', ], [ 'id' => 'T_OPEN_TAG', @@ -1061,8 +1061,8 @@ public function testDeclarations(array $expected, string $code): void TokenUtil::describe($token->EndStatement), ); } - $data[] = $token->Data[TokenData::NAMED_DECLARATION_PARTS]->toString(' '); - $data[] = $type = $token->Data[TokenData::NAMED_DECLARATION_TYPE]; + $data[] = $token->Data[TokenData::DECLARATION_PARTS]->toString(' '); + $data[] = $type = $token->Data[TokenData::DECLARATION_TYPE]; $actual[] = $data; $type = 'Type::' . Reflect::getConstantName(Type::class, $type); From 828fb83049d6cfbfea1df0c6f20ff883cb45d3e8 Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Tue, 7 Jan 2025 00:58:45 +1100 Subject: [PATCH 06/21] Reorganise `TokenFlag` and `TokenData` now that values have settled --- docs/Flags.md | 6 +-- src/Catalog/TokenData.php | 80 +++++++++++++++++++-------------------- src/Catalog/TokenFlag.php | 12 +++--- src/Token.php | 2 +- 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/docs/Flags.md b/docs/Flags.md index d1062eca..1c663150 100644 --- a/docs/Flags.md +++ b/docs/Flags.md @@ -20,9 +20,9 @@ | 9 | 512 | `TERNARY` | `Parser` | | 10 | 1024 | `FN_DOUBLE_ARROW` | `Parser` | | 11 | 2048 | `DECLARATION` | `Parser` | -| 12 | 4096 | `LIST_PARENT` | `Formatter` | -| 13 | 8192 | `LIST_ITEM` | `Formatter` | -| 14 | 16384 | `UNENCLOSED_PARENT` | `Parser` | +| 12 | 4096 | `UNENCLOSED_PARENT` | `Parser` | +| 13 | 8192 | `LIST_PARENT` | `Formatter` | +| 14 | 16384 | `LIST_ITEM` | `Formatter` | ## `Token::$Whitespace` diff --git a/src/Catalog/TokenData.php b/src/Catalog/TokenData.php index 44906958..b88e2766 100644 --- a/src/Catalog/TokenData.php +++ b/src/Catalog/TokenData.php @@ -10,93 +10,93 @@ interface TokenData { /** - * The content of a normalised DocBlock token (T_DOC_COMMENT or T_COMMENT) - * after delimiters and trailing whitespace are removed + * The non-virtual token a virtual token is bound to */ - public const COMMENT_CONTENT = 0; + public const BOUND_TO = 0; /** - * The token ID of the delimiter associated with a LIST_PARENT token + * The last non-virtual token before a virtual token, or null if there is no + * such token */ - public const LIST_DELIMITER = 1; + public const PREV_REAL = 1; /** - * A collection of items associated with a LIST_PARENT token + * The next non-virtual token after a virtual token, or null if there is no + * such token */ - public const LIST_ITEMS = 2; + public const NEXT_REAL = 2; /** - * The number of items associated with a LIST_PARENT token + * The control structure a T_OPEN_UNENCLOSED token is associated with */ - public const LIST_ITEM_COUNT = 3; + public const UNENCLOSED_PARENT = 3; /** - * The LIST_PARENT of the first token in a LIST_ITEM + * Whether or not the control structure a T_OPEN_UNENCLOSED token is + * associated with continues after its T_CLOSE_UNENCLOSED counterpart */ - public const LIST_PARENT = 4; + public const UNENCLOSED_CONTINUES = 4; /** - * The other T_QUESTION or T_COLON associated with a TERNARY + * A collection of tokens that form a DECLARATION */ - public const OTHER_TERNARY = 5; + public const DECLARATION_PARTS = 5; /** - * The last token of the string opened by the token + * The type of a DECLARATION */ - public const END_STRING = 6; + public const DECLARATION_TYPE = 6; /** - * The first object operator in a chain of method calls + * A collection of property hooks associated with a DECLARATION of type + * PROPERTY or PROMOTED_PARAM */ - public const CHAIN = 7; + public const PROPERTY_HOOKS = 7; /** - * A collection of tokens that form a DECLARATION + * The last token of the string opened by the token */ - public const DECLARATION_PARTS = 8; + public const END_STRING = 8; /** - * The type of a DECLARATION + * The first object operator in a chain of method calls */ - public const DECLARATION_TYPE = 9; + public const CHAIN = 9; /** - * A collection of property hooks associated with a DECLARATION of type - * PROPERTY or PROMOTED_PARAM + * The other T_QUESTION or T_COLON associated with a TERNARY */ - public const PROPERTY_HOOKS = 10; + public const OTHER_TERNARY = 10; /** - * An array of closures that align other tokens with the token when its - * output column changes + * The token ID of the delimiter associated with a LIST_PARENT token */ - public const ALIGNMENT_CALLBACKS = 11; + public const LIST_DELIMITER = 11; /** - * The control structure a T_OPEN_UNENCLOSED token is associated with + * A collection of items associated with a LIST_PARENT token */ - public const UNENCLOSED_PARENT = 12; + public const LIST_ITEMS = 12; /** - * Whether or not the control structure a T_OPEN_UNENCLOSED token is - * associated with continues after its T_CLOSE_UNENCLOSED counterpart + * The number of items associated with a LIST_PARENT token */ - public const UNENCLOSED_CONTINUES = 13; + public const LIST_ITEM_COUNT = 13; /** - * The non-virtual token a virtual token is bound to + * The LIST_PARENT of the first token in a LIST_ITEM */ - public const BOUND_TO = 14; + public const LIST_PARENT = 14; /** - * The last non-virtual token before a virtual token, or null if there is no - * such token + * The content of a normalised DocBlock token (T_DOC_COMMENT or T_COMMENT) + * after delimiters and trailing whitespace are removed */ - public const PREV_REAL = 15; + public const COMMENT_CONTENT = 15; /** - * The next non-virtual token after a virtual token, or null if there is no - * such token + * An array of closures that align other tokens with the token when its + * output column changes */ - public const NEXT_REAL = 16; + public const ALIGNMENT_CALLBACKS = 16; } diff --git a/src/Catalog/TokenFlag.php b/src/Catalog/TokenFlag.php index eae3d6ba..707e351b 100644 --- a/src/Catalog/TokenFlag.php +++ b/src/Catalog/TokenFlag.php @@ -87,17 +87,17 @@ interface TokenFlag public const DECLARATION = 2048; /** - * The token is the parent of a list of items + * The token is a control structure with an unenclosed body */ - public const LIST_PARENT = 4096; + public const UNENCLOSED_PARENT = 4096; /** - * The token is the first in a list item + * The token is the parent of a list of items */ - public const LIST_ITEM = 8192; + public const LIST_PARENT = 8192; /** - * The token is a control structure with an unenclosed body + * The token is the first in a list item */ - public const UNENCLOSED_PARENT = 16384; + public const LIST_ITEM = 16384; } diff --git a/src/Token.php b/src/Token.php index abbbb83f..bb3d4115 100644 --- a/src/Token.php +++ b/src/Token.php @@ -57,7 +57,7 @@ final class Token extends GenericToken implements HasTokenNames, JsonSerializabl /** * @var array - * @phpstan-var array{string,int,TokenCollection,int,self,self,self,self,TokenCollection,int,TokenCollection,Closure[],self,bool,self,self|null,self|null} + * @phpstan-var array{self,self|null,self|null,self,bool,TokenCollection,int,TokenCollection,self,self,self,int,TokenCollection,int,self,string,Closure[]} */ public array $Data; From fbd9739360752df5af84213e155e277753a04b68 Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Tue, 7 Jan 2025 01:01:51 +1100 Subject: [PATCH 07/21] Clean up `WhitespaceFlag` --- src/Catalog/WhitespaceFlag.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Catalog/WhitespaceFlag.php b/src/Catalog/WhitespaceFlag.php index e007cb0c..a0e17aaa 100644 --- a/src/Catalog/WhitespaceFlag.php +++ b/src/Catalog/WhitespaceFlag.php @@ -3,7 +3,7 @@ namespace Lkrms\PrettyPHP\Catalog; /** - * Whitespace flags applied to tokens + * Token whitespace flags * * @api */ From 90a717e909e2d506bda2e71bfdd589d0876b4519 Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Tue, 7 Jan 2025 02:33:17 +1100 Subject: [PATCH 08/21] Add tokens and declarations to `list-rules.php` output --- docs/Rules.md | 60 +++++++++++++++++++++--------------------- scripts/list-rules.php | 35 +++++++++++++++--------- 2 files changed, 52 insertions(+), 43 deletions(-) diff --git a/docs/Rules.md b/docs/Rules.md index 859bcc2c..2ceecfab 100644 --- a/docs/Rules.md +++ b/docs/Rules.md @@ -59,7 +59,7 @@ Formatting rules applied by `pretty-php` are as follows. ### `NormaliseComments` -(mandatory, `processTokens()`, priority 40) +(mandatory, `processTokens()`, priority 40, tokens: `T_COMMENT` | `T_DOC_COMMENT`) In one-line C-style comments (`/*`), unnecessary asterisks are removed from both delimiters, the remaining content is trimmed, and spaces are added between delimiters and adjacent content. @@ -81,7 +81,7 @@ Multi-line C-style comments where every line starts with an asterisk, or at leas ### `NormaliseStrings` -(default, `processTokens()`, priority 42) +(default, `processTokens()`, priority 42, tokens: `T_ENCAPSED_AND_WHITESPACE` | `T_CONSTANT_ENCAPSED_STRING`) Strings other than nowdocs are normalised as follows: @@ -91,7 +91,7 @@ Strings other than nowdocs are normalised as follows: ### `NormaliseNumbers` -(default, `processTokens()`, priority 44) +(default, `processTokens()`, priority 44, tokens: `T_LNUMBER` | `T_DNUMBER`) Integer literals are normalised by replacing hexadecimal, octal and binary prefixes with `0x`, `0` and `0b` respectively, removing redundant zeroes, and converting hexadecimal digits to uppercase. @@ -101,13 +101,13 @@ If an underscore is present in the input, underscores are applied to decimal val ### `ProtectStrings` -(mandatory, `processTokens()`, priority 60) +(mandatory, `processTokens()`, priority 60, tokens: `"` | `` ` `` | `T_START_HEREDOC`) In non-constant strings, whitespace between tokens is suppressed for inner siblings, and for every token between square brackets. (The latter is necessary because strings like `"$foo[0]"` and `"$foo[$bar]"` are unparseable if there is any whitespace between the brackets.) ### `FormatHeredocs` (1) -(mandatory, `processTokens()`, priority 62) +(mandatory, `processTokens()`, priority 62, tokens: `T_START_HEREDOC`) If `HeredocIndent` has a value other than `NONE`, heredocs are saved for later processing. @@ -124,7 +124,7 @@ Blank lines are also suppressed inside alternative syntax blocks. ### `OperatorSpacing` -(mandatory, `processTokens()`, priority 102) +(mandatory, `processTokens()`, priority 102, tokens: `!` | `$` | `%` | `&` | `*` | `+` | `-` | `.` | `/` | `:` | `<` | `=` | `>` | `?` | `@` | `^` | `|` | `~` | `T_LOGICAL_OR` | `T_LOGICAL_XOR` | `T_LOGICAL_AND` | `T_INSTANCEOF` | `T_PLUS_EQUAL` | `T_MINUS_EQUAL` | `T_MUL_EQUAL` | `T_DIV_EQUAL` | `T_CONCAT_EQUAL` | `T_MOD_EQUAL` | `T_AND_EQUAL` | `T_OR_EQUAL` | `T_XOR_EQUAL` | `T_SL_EQUAL` | `T_SR_EQUAL` | `T_COALESCE_EQUAL` | `T_BOOLEAN_OR` | `T_BOOLEAN_AND` | `T_IS_EQUAL` | `T_IS_NOT_EQUAL` | `T_IS_IDENTICAL` | `T_IS_NOT_IDENTICAL` | `T_IS_SMALLER_OR_EQUAL` | `T_IS_GREATER_OR_EQUAL` | `T_SPACESHIP` | `T_SL` | `T_SR` | `T_INC` | `T_DEC` | `T_DOUBLE_ARROW` | `T_COALESCE` | `T_POW` | `T_POW_EQUAL` | `T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG` | `T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG`) Operators in `declare` expressions are ignored. @@ -150,7 +150,7 @@ Spaces are added before and after operators not mentioned above. ### `StandardSpacing` (1) -(mandatory, `processTokens()`, priority 104) +(mandatory, `processTokens()`, priority 104, tokens: `,` | `T_DECLARE` | `T_MATCH` | `T_ATTRIBUTE` | `T_OPEN_TAG` | `T_OPEN_TAG_WITH_ECHO` | `T_CLOSE_TAG` | `T_START_HEREDOC` | `T_ATTRIBUTE_COMMENT`) If the indentation level of an open tag aligns with a tab stop, and a close tag is found in the same scope (or the document has no close tag, and the open tag is in the global scope), a callback is registered to align nested tokens with it. An additional level of indentation is applied if `IndentBetweenTags` is enabled. @@ -168,7 +168,7 @@ Whitespace is applied to other tokens as follows: ### `StandardSpacing` (2) -(mandatory, `processDeclarations()`, priority 104) +(mandatory, `processDeclarations()`, priority 104, declarations: `PROPERTY` | `PARAM`) If a constructor has one or more promoted parameters, a newline is added before every parameter. @@ -176,7 +176,7 @@ If a property has unimplemented hooks with no modifiers or attributes (e.g. `pub ### `StatementSpacing` -(mandatory, `processTokens()`, priority 120) +(mandatory, `processTokens()`, priority 120, tokens: `:` | `;`) In `for` loop expressions, a space is added after semicolons where the next expression is not empty. @@ -184,7 +184,7 @@ Whitespace is suppressed before, and newlines are added after, semicolons in oth ### `ControlStructureSpacing` -(mandatory, `processTokens()`, priority 122) +(mandatory, `processTokens()`, priority 122, tokens: `T_IF` | `T_ELSEIF` | `T_ELSE` | `T_DO` | `T_WHILE` | `T_FOR` | `T_FOREACH`) If the body of a control structure has no enclosing braces: @@ -195,7 +195,7 @@ If the body of a control structure has no enclosing braces: ### `PlaceBraces` (1) -(mandatory, `processTokens()`, priority 124) +(mandatory, `processTokens()`, priority 124, tokens: `{`) Whitespace is applied to structural and `match` expression braces as follows: @@ -209,7 +209,7 @@ Whitespace is applied to structural and `match` expression braces as follows: ### `PlaceComments` (1) -(mandatory, `processTokens()`, priority 126) +(mandatory, `processTokens()`, priority 126, tokens: `T_COMMENT` | `T_DOC_COMMENT`) Critical newlines are added after one-line comments followed by any token other than a close tag. @@ -231,7 +231,7 @@ For multi-line DocBlocks, and C-style comments that receive the same treatment: ### `PreserveNewlines` -(default, `processTokens()`, priority 200) +(default, `processTokens()`, priority 200, tokens: `* (except virtual)`) If a newline in the input is adjacent to a token in `AllowNewlineBefore` or `AllowNewlineAfter`, it is applied to the token as a leading or trailing newline on a best-effort basis. This has the effect of placing operators before or after newlines as per the formatter's token index. @@ -254,13 +254,13 @@ Attributes on their own line are excluded from consideration. ### `BlankBeforeReturn` -(optional, `processTokens()`, priority 220) +(optional, `processTokens()`, priority 220, tokens: `T_YIELD` | `T_YIELD_FROM` | `T_RETURN`) Blank lines are added before non-consecutive `return`, `yield` and `yield from` statements. ### `VerticalSpacing` (1) -(mandatory, `processTokens()`, priority 240) +(mandatory, `processTokens()`, priority 240, tokens: `&` | `?` | `^` | `{` | `|` | `T_LOGICAL_OR` | `T_LOGICAL_XOR` | `T_LOGICAL_AND` | `T_FOR` | `T_BOOLEAN_OR` | `T_BOOLEAN_AND` | `T_OBJECT_OPERATOR` | `T_NULLSAFE_OBJECT_OPERATOR` | `T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG` | `T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG`) In expressions where one or more boolean operators have an adjacent newline, newlines are added to other boolean operators of equal or lower precedence. @@ -289,7 +289,7 @@ If parameter lists have one or more attributes with a trailing newline, every at ### `VerticalSpacing` (3) -(mandatory, `processDeclarations()`, priority 240) +(mandatory, `processDeclarations()`, priority 240, declarations: `CONST` | `USE` | `PROPERTY` | `PARAM` | `USE_CONST` | `USE_FUNCTION` | `USE_TRAIT`) Newlines are added between comma-delimited constant declarations and property declarations. When neither `StrictLists` nor `AlignLists` are enabled, they are also added to `use` statements between comma-delimited imports and trait insertions that break over multiple lines. @@ -303,13 +303,13 @@ Items in lists are arranged horizontally or vertically by replicating the arrang ### `StrictExpressions` -(optional, `processTokens()`, priority 244) +(optional, `processTokens()`, priority 244, tokens: `T_IF` | `T_ELSEIF` | `T_WHILE` | `T_FOR` | `T_FOREACH` | `T_SWITCH`) Newlines are added before and after control structure expressions that break over multiple lines. ### `SemiStrictExpressions` -(optional, `processTokens()`, priority 246) +(optional, `processTokens()`, priority 246, tokens: `T_IF` | `T_ELSEIF` | `T_WHILE` | `T_FOR` | `T_FOREACH` | `T_SWITCH`) Newlines are added before and after control structure expressions with newlines between siblings. @@ -317,7 +317,7 @@ Newlines are added before and after control structure expressions with newlines ### `AlignChains` (1) -(optional, `processTokens()`, priority 280) +(optional, `processTokens()`, priority 280, tokens: `T_OBJECT_OPERATOR` | `T_NULLSAFE_OBJECT_OPERATOR`) If there are no object operators with a leading newline in a chain of method calls, or if the first object operator in the chain has a leading newline and `AlignChainAfterNewline` is disabled, no action is taken. @@ -329,7 +329,7 @@ Otherwise, if the first object operator in the chain has a leading newline, it i ### `DeclarationSpacing` -(default, `processDeclarations()`, priority 299) +(default, `processDeclarations()`, priority 299, declarations: `CASE` | `CLASS` | `CONST` | `DECLARE` | `ENUM` | `FUNCTION` | `INTERFACE` | `NAMESPACE` | `TRAIT` | `USE` | `PROPERTY` | `HOOK` | `USE_CONST` | `USE_FUNCTION` | `USE_TRAIT`) One-line declarations with a collapsed or collapsible DocBlock, or no DocBlock at all, are considered "collapsible". Declarations that break over multiple lines or have a DocBlock that cannot be collapsed to one line are considered "non-collapsible". @@ -346,13 +346,13 @@ Blank lines are also added before and after each group of declarations. They are ### `StandardIndentation` -(mandatory, `processTokens()`, priority 300) +(mandatory, `processTokens()`, priority 300, tokens: `*`) The `Indent` and inner whitespace of each open bracket is copied to its close bracket, and the `Indent` of tokens between brackets with inner newlines is incremented. ### `SwitchIndentation` -(mandatory, `processTokens()`, priority 302) +(mandatory, `processTokens()`, priority 302, tokens: `T_SWITCH` | `T_CASE` | `T_DEFAULT`) In switch case lists: @@ -363,7 +363,7 @@ In switch case lists: ### `AlignArrowFunctions` (1) -(optional, `processTokens()`, priority 320) +(optional, `processTokens()`, priority 320, tokens: `T_FN`) If an arrow function expression starts on a new line, a callback is registered to align it with the `fn` it's associated with, or with the first token on the previous line if its arguments break over multiple lines. @@ -375,19 +375,19 @@ A callback is registered to align arguments, array elements and other list items ### `AlignTernaryOperators` (1) -(optional, `processTokens()`, priority 324) +(optional, `processTokens()`, priority 324, tokens: `?` | `T_COALESCE`) If a ternary or null coalescing operator has a leading newline, a callback is registered to align it with its expression, or with the first token on the previous line if its expression breaks over multiple lines. ### `HangingIndentation` (1) -(mandatory, `processTokens()`, priority 380) +(mandatory, `processTokens()`, priority 380, tokens: `*`) Scopes and expressions that would otherwise be difficult to differentiate from adjacent code are indented for visual separation, and a callback is registered to collapse any unnecessary "overhanging" indentation levels. ### `Symfony` (1) -(optional, `processTokens()`, priority 400) +(optional, `processTokens()`, priority 400, tokens: `.` | `T_FN`) Trailing spaces are added to `fn` in arrow functions. @@ -401,7 +401,7 @@ Newlines are suppressed between parameters in function declarations that have no ### `Drupal` (1) -(optional, `processTokens()`, priority 420) +(optional, `processTokens()`, priority 420, tokens: `T_ELSEIF` | `T_ELSE` | `T_CATCH` | `T_FINALLY` | `T_DOC_COMMENT`) Blank lines are added after DocBlocks with a `@file` tag. @@ -409,13 +409,13 @@ Newlines are added after close braces with a subsequent `elseif`, `else`, `catch ### `Drupal` (2) -(optional, `processDeclarations()`, priority 420) +(optional, `processDeclarations()`, priority 420, declarations: `CLASS` | `ENUM` | `INTERFACE` | `TRAIT`) Blank lines are added inside non-empty `class`, `enum`, `interface` and `trait` braces. ### `Laravel` -(optional, `processTokens()`, priority 440) +(optional, `processTokens()`, priority 440, tokens: `!` | `.` | `T_FN`) Trailing spaces are added to: @@ -426,7 +426,7 @@ Leading and trailing spaces are suppressed for `.` operators. ### `WordPress` -(optional, `processTokens()`, priority 480) +(optional, `processTokens()`, priority 480, tokens: `!` | `(` | `:` | `[` | `{` | `T_COMMENT` | `T_DOC_COMMENT`) Suppression of blank lines after DocBlocks is removed for the first DocBlock in each document. diff --git a/scripts/list-rules.php b/scripts/list-rules.php index 53cad52c..830cacc7 100755 --- a/scripts/list-rules.php +++ b/scripts/list-rules.php @@ -201,30 +201,34 @@ function printTable(array $table): void $r['priority'], ]; - if (!in_array($r['rule'], [ - IndexSpacing::class, - OperatorSpacing::class, - ], true)) { - if (is_string($r['tokens'][0] ?? null)) { - $tokenRules[$r['tokens'][0]][] = $heading; - } elseif ($r['tokens']) { - foreach (array_keys(array_filter($r['tokens'])) as $id) { - $name = token_name($id); - if (!Str::startsWith($name, 'T_')) { - $name = HasTokenNames::TOKEN_NAME[$id] ?? $name; - } + $tokens = null; + if (is_string($r['tokens'][0] ?? null)) { + $tokenRules[$r['tokens'][0]][] = $heading; + $tokens[] = $r['tokens'][0]; + } elseif ($r['tokens'] && $r['rule'] !== IndexSpacing::class) { + $tokenIds = array_keys(array_filter($r['tokens'])); + sort($tokenIds, \SORT_NUMERIC); + foreach ($tokenIds as $id) { + $name = HasTokenNames::TOKEN_NAME[$id] ?? token_name($id); + if ($r['rule'] !== OperatorSpacing::class) { $tokenRules[$name][] = $heading; } + $tokens[] = $id < 256 + ? ($id === \T_BACKTICK ? '` ` `' : chr($id)) + : $name; } } + $declarations = null; if ($r['declarations'] === ['*']) { $declarationRules['*'][] = $heading; + $declarations[] = '*'; } elseif ($r['declarations']) { foreach (array_keys(array_filter($r['declarations'])) as $id) { $name = Reflect::getConstantName(DeclarationType::class, $id); $name = ltrim($name, '_'); $declarationRules[$name][] = $heading; + $declarations[] = $name; } } @@ -252,7 +256,12 @@ function printTable(array $table): void ? 'default' : 'optional' ) - ) . ', ' . $method . ', priority ' . $r['priority'] . ')'; + ) . ', ' . $method . ', priority ' . $r['priority'] . ( + ($with = $tokens ?? $declarations) + ? ', ' . ($tokens ? 'tokens' : 'declarations') + . ': `' . implode('` | `', $with) . '`' + : '' + ) . ')'; // Remove leading ">" after non-empty lines $description = Regex::replace('/(? ?/m', '$1', $description ?? 'Not documented.'); $docs[] = Str::unwrap($description, "\n", false, true, true); From 50c83721eecd880f37ecf625e03d5ce4cd5a28db Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Tue, 7 Jan 2025 11:40:05 +1100 Subject: [PATCH 09/21] Clean up `TokenIndex`, rename `T_END_ALT_SYNTAX` to `T_CLOSE_ALT` - Add `OperatorExceptTernaryOrDelimiter` - Replace `AltContinue` with `AltContinueOrEnd` - Remove `OpenBracketOrAlt`, `CloseBracketOrAlt`, `AltContinueWithExpression`, `AltContinueWithNoExpression`, `IfElseIfOrElse`, `OperatorTernary` `ExpressionDelimiter` - Rename other indexes for brevity or clarity --- .php-cs-fixer.dist.php | 2 +- bootstrap.php | 4 +- src/Concern/FilterTrait.php | 4 +- src/Contract/HasTokenIndex.php | 31 +++- src/Contract/HasTokenNames.php | 2 +- src/Parser.php | 17 +- src/Rule/AlignData.php | 6 +- src/Rule/BlankBeforeReturn.php | 4 +- src/Rule/DeclarationSpacing.php | 2 +- src/Rule/HangingIndentation.php | 18 +- src/Rule/IndexSpacing.php | 10 +- src/Rule/VerticalSpacing.php | 8 +- src/Token.php | 8 +- src/TokenIndex.php | 162 ++++++------------ tests/integration/Bootstrap/BootstrapTest.php | 2 +- .../integration/Bootstrap/invalid-tokens.php | 2 +- .../Bootstrap/tokens-with-same-id.php | 2 +- tests/unit/ParserTest.php | 8 +- tests/unit/TokenIndexTest.php | 5 +- 19 files changed, 127 insertions(+), 170 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 891b5ce1..8db105a9 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -6,7 +6,7 @@ 'T_PUBLIC_SET', 'T_PROPERTY_C', 'T_ATTRIBUTE_COMMENT', - 'T_END_ALT_SYNTAX', + 'T_CLOSE_ALT', 'T_NULL', 'T_OPEN_UNENCLOSED', 'T_CLOSE_UNENCLOSED', diff --git a/bootstrap.php b/bootstrap.php index a63fc00f..07c00ae7 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -21,7 +21,7 @@ 'T_PROPERTY_C' => false, // Custom 'T_ATTRIBUTE_COMMENT' => false, - 'T_END_ALT_SYNTAX' => false, + 'T_CLOSE_ALT' => false, 'T_NULL' => false, 'T_OPEN_UNENCLOSED' => false, 'T_CLOSE_UNENCLOSED' => false, @@ -80,7 +80,7 @@ // Define custom tokens $id = 20000; defined('T_ATTRIBUTE_COMMENT') || define('T_ATTRIBUTE_COMMENT', $getNextId()); - defined('T_END_ALT_SYNTAX') || define('T_END_ALT_SYNTAX', $getNextId()); + defined('T_CLOSE_ALT') || define('T_CLOSE_ALT', $getNextId()); defined('T_NULL') || define('T_NULL', $getNextId()); defined('T_OPEN_UNENCLOSED') || define('T_OPEN_UNENCLOSED', $getNextId()); defined('T_CLOSE_UNENCLOSED') || define('T_CLOSE_UNENCLOSED', $getNextId()); diff --git a/src/Concern/FilterTrait.php b/src/Concern/FilterTrait.php index bfbb3267..83bac006 100644 --- a/src/Concern/FilterTrait.php +++ b/src/Concern/FilterTrait.php @@ -206,11 +206,11 @@ private function isColonAltSyntaxDelimiter(int $i): bool { /** @var GenericToken */ $token = $this->getPrevCode($i, $j); - return $this->Idx->AltContinueWithNoExpression[$token->id] + return $token->id === \T_ELSE || ( $token->id === \T_CLOSE_PARENTHESIS && ($prev = $this->getPrevSibling($j)) - && $this->Idx->AltStartOrContinueWithExpression[$prev->id] + && $this->Idx->AltStartOrContinue[$prev->id] ); } diff --git a/src/Contract/HasTokenIndex.php b/src/Contract/HasTokenIndex.php index 7a171b59..8308035e 100644 --- a/src/Contract/HasTokenIndex.php +++ b/src/Contract/HasTokenIndex.php @@ -35,6 +35,7 @@ interface HasTokenIndex \T_CLASS => false, \T_CLASS_C => false, \T_CLONE => false, + \T_CLOSE_ALT => false, \T_CLOSE_BRACE => false, \T_CLOSE_BRACKET => false, \T_CLOSE_PARENTHESIS => false, @@ -72,7 +73,6 @@ interface HasTokenIndex \T_ELSEIF => false, \T_EMPTY => false, \T_ENCAPSED_AND_WHITESPACE => false, - \T_END_ALT_SYNTAX => false, \T_END_HEREDOC => false, \T_ENDDECLARE => false, \T_ENDFOR => false, @@ -224,6 +224,7 @@ interface HasTokenIndex \T_CLASS => true, \T_CLASS_C => true, \T_CLONE => true, + \T_CLOSE_ALT => true, \T_CLOSE_BRACE => true, \T_CLOSE_BRACKET => true, \T_CLOSE_PARENTHESIS => true, @@ -261,7 +262,6 @@ interface HasTokenIndex \T_ELSEIF => true, \T_EMPTY => true, \T_ENCAPSED_AND_WHITESPACE => true, - \T_END_ALT_SYNTAX => true, \T_END_HEREDOC => true, \T_ENDDECLARE => true, \T_ENDFOR => true, @@ -662,22 +662,27 @@ interface HasTokenIndex /** * @var array */ - public const VISIBILITY = [ - \T_PRIVATE_SET => true, - \T_PROTECTED_SET => true, - \T_PUBLIC_SET => true, - ] - + self::VISIBILITY_GET; + public const VISIBILITY = self::VISIBILITY_SYMMETRIC + + self::VISIBILITY_ASYMMETRIC; /** * @var array */ - public const VISIBILITY_GET = [ + public const VISIBILITY_SYMMETRIC = [ \T_PRIVATE => true, \T_PROTECTED => true, \T_PUBLIC => true, ]; + /** + * @var array + */ + public const VISIBILITY_ASYMMETRIC = [ + \T_PRIVATE_SET => true, + \T_PROTECTED_SET => true, + \T_PUBLIC_SET => true, + ]; + /** * @var array */ @@ -783,6 +788,14 @@ interface HasTokenIndex \T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG => true, ]; + /** + * @var array + */ + public const ATTRIBUTE = [ + \T_ATTRIBUTE => true, + \T_ATTRIBUTE_COMMENT => true, + ]; + /** * @var array */ diff --git a/src/Contract/HasTokenNames.php b/src/Contract/HasTokenNames.php index fe3a45f1..f000e3bb 100644 --- a/src/Contract/HasTokenNames.php +++ b/src/Contract/HasTokenNames.php @@ -30,7 +30,7 @@ interface HasTokenNames \T_PROPERTY_C => 'T_PROPERTY_C', // Custom \T_ATTRIBUTE_COMMENT => 'T_ATTRIBUTE_COMMENT', - \T_END_ALT_SYNTAX => 'T_END_ALT_SYNTAX', + \T_CLOSE_ALT => 'T_CLOSE_ALT', \T_NULL => 'T_NULL', \T_OPEN_UNENCLOSED => 'T_OPEN_UNENCLOSED', \T_CLOSE_UNENCLOSED => 'T_CLOSE_UNENCLOSED', diff --git a/src/Parser.php b/src/Parser.php index d2acae11..5f39f6d7 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -268,7 +268,7 @@ private function buildHierarchy( // Don't enclose tokens in alternative syntax constructs && !( $next->id === \T_COLON - && $idx->AltContinueWithNoExpression[$prevCode->id] + && $prevCode->id === \T_ELSE ) // Treat `else if` as `elseif` && !( @@ -282,7 +282,7 @@ private function buildHierarchy( // Don't enclose tokens in alternative syntax constructs && !( $next->id === \T_COLON - && $idx->AltStartOrContinueWithExpression[$parent->id] + && $idx->AltStartOrContinue[$parent->id] ) // Don't enclose tokens after `while` in `do ... while` && !( @@ -353,27 +353,26 @@ private function buildHierarchy( } // Add virtual "brackets" around alternative syntax blocks by adding - // `T_END_ALT_SYNTAX` tokens as close brackets for `T_COLON` + // `T_CLOSE_ALT` tokens as close brackets for `T_COLON` if ( - $idx->AltContinue[$token->id] - || $idx->AltEnd[$token->id] + $idx->AltContinueOrEnd[$token->id] ) { /** @var Token $prev */ - if ($prev->id !== \T_END_ALT_SYNTAX && (( + if ($prev->id !== \T_CLOSE_ALT && (( $prev->Parent && $prev->Parent->id === \T_COLON && ($idx->AltEnd[$token->id] || ( - $idx->AltContinueWithExpression[$token->id] + $token->id === \T_ELSEIF && $this->nextSibling($token, 2)->id === \T_COLON ) || ( - $idx->AltContinueWithNoExpression[$token->id] + $token->id === \T_ELSE && $this->nextSibling($token)->id === \T_COLON )) ) || ( $prev->id === \T_COLON && $prev->isColonAltSyntaxDelimiter() ))) { - $insertVirtual(\T_END_ALT_SYNTAX); + $insertVirtual(\T_CLOSE_ALT); } } diff --git a/src/Rule/AlignData.php b/src/Rule/AlignData.php index d2b381de..052b939c 100644 --- a/src/Rule/AlignData.php +++ b/src/Rule/AlignData.php @@ -102,7 +102,7 @@ public function processBlock(array $lines): void foreach ($lines as $line => $tokens) { foreach ($tokens as $token) { - if ($this->Idx->OperatorAssignment[$token->id]) { + if ($this->Idx->Assignment[$token->id]) { /** @var Token */ $prev = $token->Prev; /** @var Token */ @@ -117,10 +117,10 @@ public function processBlock(array $lines): void // - in the statement // - on the line && !$statement->withNextSiblings($prev) - ->hasOneFrom($this->Idx->OperatorAssignment) + ->hasOneFrom($this->Idx->Assignment) && !$token->firstSiblingAfterNewline(false) ->withNextSiblings($prev) - ->hasOneFrom($this->Idx->OperatorAssignment) + ->hasOneFrom($this->Idx->Assignment) ) { $addToIndex(self::TYPE_ASSIGNMENT, $line, $token); } diff --git a/src/Rule/BlankBeforeReturn.php b/src/Rule/BlankBeforeReturn.php index 4e2fdeb8..a354f7e1 100644 --- a/src/Rule/BlankBeforeReturn.php +++ b/src/Rule/BlankBeforeReturn.php @@ -31,7 +31,7 @@ public static function getPriority(string $method): ?int */ public static function getTokens(TokenIndex $idx): array { - return $idx->Return; + return $idx->ReturnOrYield; } /** @@ -64,7 +64,7 @@ public function processTokens(array $tokens): void if ( ($prev = $token->skipPrevEmptyStatements()->PrevSibling) && $prev->Statement - && $this->Idx->Return[$prev->Statement->id] + && $this->Idx->ReturnOrYield[$prev->Statement->id] ) { continue; } diff --git a/src/Rule/DeclarationSpacing.php b/src/Rule/DeclarationSpacing.php index 24a7d8b2..c780e9a4 100644 --- a/src/Rule/DeclarationSpacing.php +++ b/src/Rule/DeclarationSpacing.php @@ -115,7 +115,7 @@ public function processDeclarations(array $declarations): void if ($type & self::MODIFIER_MASK) { if ( $type & self::VISIBILITY_MASK - && ($modifier = $parts->getFirstFrom($this->Idx->GetVisibility)) + && ($modifier = $parts->getFirstFrom($this->Idx->SymmetricVisibility)) ) { $modifiers[] = $modifier->id; } diff --git a/src/Rule/HangingIndentation.php b/src/Rule/HangingIndentation.php index 478dd359..90c9f8e0 100644 --- a/src/Rule/HangingIndentation.php +++ b/src/Rule/HangingIndentation.php @@ -269,13 +269,13 @@ public function processTokens(array $tokens): void ? $prevCode : $token; - if ($this->Idx->OperatorAssignmentOrDoubleArrow[$trigger->id]) { + if ($this->Idx->AssignmentOrDoubleArrow[$trigger->id]) { $assignment = $trigger; } else { $assignment = null; $t = $token; do { - $t = $t->prevSiblingFrom($this->Idx->OperatorAssignmentOrDoubleArrow, true); + $t = $t->prevSiblingFrom($this->Idx->AssignmentOrDoubleArrow, true); if ($t->id === \T_NULL) { break; } @@ -341,12 +341,12 @@ public function processTokens(array $tokens): void } elseif ($statement !== $token) { // Don't indent subsequent assignments in the same statement if ( - $this->Idx->OperatorAssignment[$trigger->id] + $this->Idx->Assignment[$trigger->id] && $lastToken && $lastToken->PrevCode && ( - $this->Idx->OperatorAssignment[$lastToken->PrevCode->id] - || $this->Idx->OperatorAssignment[$lastToken->id] + $this->Idx->Assignment[$lastToken->PrevCode->id] + || $this->Idx->Assignment[$lastToken->id] ) ) { continue; @@ -392,13 +392,13 @@ public function processTokens(array $tokens): void && !$context[1] && $parent && $parentFlags & self::NO_INDENT - && !$this->Idx->OperatorAssignmentOrDoubleArrow[$trigger->id] + && !$this->Idx->AssignmentOrDoubleArrow[$trigger->id] ) || ( $lastToken && $lastToken->PrevCode && ( - $this->Idx->OperatorAssignmentOrDoubleArrow[$lastToken->PrevCode->id] - || $this->Idx->OperatorAssignmentOrDoubleArrow[$lastToken->id] + $this->Idx->AssignmentOrDoubleArrow[$lastToken->PrevCode->id] + || $this->Idx->AssignmentOrDoubleArrow[$lastToken->id] ) ); } @@ -430,7 +430,7 @@ public function processTokens(array $tokens): void // Indent expressions relative to assignment operators if ( ($next = $until->NextCode) - && $this->Idx->OperatorAssignment[$next->id] + && $this->Idx->Assignment[$next->id] ) { $until = TokenUtil::getOperatorEndExpression($next); } diff --git a/src/Rule/IndexSpacing.php b/src/Rule/IndexSpacing.php index 02bf6e7b..7211df2a 100644 --- a/src/Rule/IndexSpacing.php +++ b/src/Rule/IndexSpacing.php @@ -33,13 +33,17 @@ public static function getPriority(string $method): ?int public static function getTokens(TokenIndex $idx): array { return TokenIndex::merge( + [ + \T_COLON => true, + \T_CLOSE_ALT => true, + ], $idx->AddSpace, $idx->AddSpaceBefore, $idx->AddSpaceAfter, $idx->SuppressSpaceBefore, $idx->SuppressSpaceAfter, - $idx->OpenBracketOrAlt, - $idx->CloseBracketOrAlt, + $idx->OpenBracket, + $idx->CloseBracket, ); } @@ -95,7 +99,7 @@ public function processTokens(array $tokens): void ) )) { $token->Whitespace |= Space::NO_BLANK_BEFORE | Space::NO_SPACE_BEFORE; - } elseif ($token->id === \T_END_ALT_SYNTAX) { + } elseif ($token->id === \T_CLOSE_ALT) { $token->Whitespace |= Space::NO_BLANK_BEFORE; } } diff --git a/src/Rule/VerticalSpacing.php b/src/Rule/VerticalSpacing.php index 3fe4ee05..a866a2cc 100644 --- a/src/Rule/VerticalSpacing.php +++ b/src/Rule/VerticalSpacing.php @@ -62,7 +62,7 @@ public static function getTokens(TokenIndex $idx): array \T_QUESTION => true, ], $idx->Chain, - $idx->OperatorBooleanExceptNot, + $idx->BooleanExceptNot, ); } @@ -153,7 +153,7 @@ public function boot(): void } }; - foreach (array_keys(array_filter($this->Idx->OperatorBooleanExceptNot)) as $id) { + foreach (array_keys(array_filter($this->Idx->BooleanExceptNot)) as $id) { if ( $this->Idx->AllowNewlineBefore[$id] || !$this->Idx->AllowNewlineAfter[$id] @@ -209,7 +209,7 @@ public function processTokens(array $tokens): void foreach ($tokens as $token) { // Propagate newlines adjacent to boolean operators to others of // equal or lower precedence in the same statement - if ($this->Idx->OperatorBooleanExceptNot[$token->id]) { + if ($this->Idx->BooleanExceptNot[$token->id]) { /** @var Token */ $statement = $token->Statement; @@ -234,7 +234,7 @@ public function processTokens(array $tokens): void foreach ($statement->withNextSiblings($token->EndStatement) as $t) { if ( $t === $token - || !$this->Idx->OperatorBooleanExceptNot[$t->id] + || !$this->Idx->BooleanExceptNot[$t->id] ) { continue; } diff --git a/src/Token.php b/src/Token.php index bb3d4115..9905e13a 100644 --- a/src/Token.php +++ b/src/Token.php @@ -569,11 +569,11 @@ private function getColonSubId(): int if ( $this->CloseBracket - || $this->Idx->AltContinueWithNoExpression[$prevCode->id] + || $prevCode->id === \T_ELSE || ( $prevCode->id === \T_CLOSE_PARENTHESIS && ($prev = $prevCode->PrevSibling) - && $this->Idx->AltStartOrContinueWithExpression[$prev->id] + && $this->Idx->AltStartOrContinue[$prev->id] ) ) { return TokenSubId::COLON_ALT_SYNTAX_DELIMITER; @@ -733,7 +733,7 @@ public function isArrayOpenBracket(): bool public function isUnaryOperator(): bool { - return $this->Idx->OperatorUnary[$this->id] || ( + return $this->Idx->Unary[$this->id] || ( $this->Idx->PlusOrMinus[$this->id] && $this->inUnaryContext() ); @@ -1008,7 +1008,7 @@ private function isDeclaration(): bool public function skipToStartOfDeclaration(): self { if ( - $this->Idx->ExpressionDelimiter[$this->id] + $this->Idx->OperatorExceptTernaryOrDelimiter[$this->id] || $this->Flags & TokenFlag::TERNARY ) { // @codeCoverageIgnoreStart diff --git a/src/TokenIndex.php b/src/TokenIndex.php index 92da773f..bf333f2f 100644 --- a/src/TokenIndex.php +++ b/src/TokenIndex.php @@ -88,17 +88,6 @@ class TokenIndex implements HasTokenIndex, Immutable public array $OpenBracket = self::OPEN_BRACKET + self::TOKEN_INDEX; - /** - * T_OPEN_BRACE, T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_ATTRIBUTE, - * T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES, T_COLON - * - * @var array - */ - public array $OpenBracketOrAlt = self::OPEN_BRACKET + [ - \T_COLON => true, - ] - + self::TOKEN_INDEX; - /** * T_OPEN_BRACE, T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_ATTRIBUTE, * T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES, T_LOGICAL_NOT, T_NOT @@ -119,16 +108,6 @@ class TokenIndex implements HasTokenIndex, Immutable public array $CloseBracket = self::CLOSE_BRACKET + self::TOKEN_INDEX; - /** - * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_END_ALT_SYNTAX - * - * @var array - */ - public array $CloseBracketOrAlt = self::CLOSE_BRACKET + [ - \T_END_ALT_SYNTAX => true, - ] - + self::TOKEN_INDEX; - /** * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_COMMA * @@ -141,13 +120,13 @@ class TokenIndex implements HasTokenIndex, Immutable /** * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_CLOSE_UNENCLOSED, - * T_END_ALT_SYNTAX + * T_CLOSE_ALT * * @var array */ public array $CloseBracketOrVirtual = self::CLOSE_BRACKET + [ \T_CLOSE_UNENCLOSED => true, - \T_END_ALT_SYNTAX => true, + \T_CLOSE_ALT => true, ] + self::TOKEN_INDEX; @@ -214,7 +193,7 @@ class TokenIndex implements HasTokenIndex, Immutable * * @var array */ - public array $AltStartOrContinueWithExpression = [ + public array $AltStartOrContinue = [ \T_DECLARE => true, \T_FOR => true, \T_FOREACH => true, @@ -226,33 +205,20 @@ class TokenIndex implements HasTokenIndex, Immutable + self::TOKEN_INDEX; /** - * T_ELSE, T_ELSEIF + * T_ELSEIF, T_ELSE, T_ENDDECLARE, T_ENDFOR, T_ENDFOREACH, T_ENDIF, + * T_ENDSWITCH, T_ENDWHILE * * @var array */ - public array $AltContinue = [ + public array $AltContinueOrEnd = [ \T_ELSEIF => true, \T_ELSE => true, - ] - + self::TOKEN_INDEX; - - /** - * T_ELSEIF - * - * @var array - */ - public array $AltContinueWithExpression = [ - \T_ELSEIF => true, - ] - + self::TOKEN_INDEX; - - /** - * T_ELSE - * - * @var array - */ - public array $AltContinueWithNoExpression = [ - \T_ELSE => true, + \T_ENDDECLARE => true, + \T_ENDFOR => true, + \T_ENDFOREACH => true, + \T_ENDIF => true, + \T_ENDSWITCH => true, + \T_ENDWHILE => true, ] + self::TOKEN_INDEX; @@ -285,10 +251,7 @@ class TokenIndex implements HasTokenIndex, Immutable * * @var array */ - public array $Attribute = [ - \T_ATTRIBUTE => true, - \T_ATTRIBUTE_COMMENT => true, - ] + public array $Attribute = self::ATTRIBUTE + self::TOKEN_INDEX; /** @@ -298,10 +261,7 @@ class TokenIndex implements HasTokenIndex, Immutable * * @var array */ - public array $AttributeOrDeclaration = [ - \T_ATTRIBUTE => true, - \T_ATTRIBUTE_COMMENT => true, - ] + public array $AttributeOrDeclaration = self::ATTRIBUTE + self::DECLARATION + self::TOKEN_INDEX; @@ -311,10 +271,7 @@ class TokenIndex implements HasTokenIndex, Immutable * * @var array */ - public array $AttributeOrModifier = [ - \T_ATTRIBUTE => true, - \T_ATTRIBUTE_COMMENT => true, - ] + public array $AttributeOrModifier = self::ATTRIBUTE + self::MODIFIER + self::TOKEN_INDEX; @@ -323,9 +280,7 @@ class TokenIndex implements HasTokenIndex, Immutable * * @var array */ - public array $AttributeOrStatic = [ - \T_ATTRIBUTE => true, - \T_ATTRIBUTE_COMMENT => true, + public array $AttributeOrStatic = self::ATTRIBUTE + [ \T_STATIC => true, ] + self::TOKEN_INDEX; @@ -501,7 +456,7 @@ class TokenIndex implements HasTokenIndex, Immutable * * @var array */ - public array $GetVisibility = self::VISIBILITY_GET + public array $SymmetricVisibility = self::VISIBILITY_SYMMETRIC + self::TOKEN_INDEX; /** @@ -526,18 +481,6 @@ class TokenIndex implements HasTokenIndex, Immutable ] + self::TOKEN_INDEX; - /** - * T_IF, T_ELSEIF, T_ELSE - * - * @var array - */ - public array $IfElseIfOrElse = [ - \T_IF => true, - \T_ELSEIF => true, - \T_ELSE => true, - ] - + self::TOKEN_INDEX; - /** * T_INLINE_HTML, T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG * @@ -635,12 +578,38 @@ class TokenIndex implements HasTokenIndex, Immutable + self::OPERATOR_TERNARY + self::TOKEN_INDEX; + /** + * Arithmetic operators, assignment operators, bitwise operators (except + * T_OR, T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG), comparison operators, + * logical operators, T_AT, T_CONCAT, T_DOLLAR, T_DOUBLE_ARROW, T_INC, + * T_DEC, T_INSTANCEOF + * + * @var array + */ + public array $OperatorExceptTernaryOrDelimiter = [ + \T_AT => true, + \T_CONCAT => true, + \T_DOLLAR => true, + \T_DOUBLE_ARROW => true, + \T_INC => true, + \T_DEC => true, + \T_INSTANCEOF => true, + \T_OR => false, + \T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG => false, + ] + + self::OPERATOR_ARITHMETIC + + self::OPERATOR_ASSIGNMENT + + self::OPERATOR_BITWISE + + self::OPERATOR_COMPARISON + + self::OPERATOR_LOGICAL + + self::TOKEN_INDEX; + /** * Assignment operators * * @var array */ - public array $OperatorAssignment = self::OPERATOR_ASSIGNMENT + public array $Assignment = self::OPERATOR_ASSIGNMENT + self::TOKEN_INDEX; /** @@ -648,7 +617,7 @@ class TokenIndex implements HasTokenIndex, Immutable * * @var array */ - public array $OperatorAssignmentOrDoubleArrow = [ + public array $AssignmentOrDoubleArrow = [ \T_DOUBLE_ARROW => true, ] + self::OPERATOR_ASSIGNMENT @@ -663,7 +632,7 @@ class TokenIndex implements HasTokenIndex, Immutable * * @var array */ - public array $OperatorBooleanExceptNot = [ + public array $BooleanExceptNot = [ \T_OR => true, \T_XOR => true, \T_LOGICAL_NOT => false, @@ -672,20 +641,12 @@ class TokenIndex implements HasTokenIndex, Immutable + self::AMPERSAND + self::TOKEN_INDEX; - /** - * Ternary operators - * - * @var array - */ - public array $OperatorTernary = self::OPERATOR_TERNARY - + self::TOKEN_INDEX; - /** * T_AT, T_DEC, T_DOLLAR, T_INC, T_LOGICAL_NOT, T_NOT * * @var array */ - public array $OperatorUnary = [ + public array $Unary = [ \T_AT => true, \T_DOLLAR => true, \T_INC => true, @@ -711,7 +672,7 @@ class TokenIndex implements HasTokenIndex, Immutable * * @var array */ - public array $Return = [ + public array $ReturnOrYield = [ \T_RETURN => true, \T_YIELD => true, \T_YIELD_FROM => true, @@ -758,24 +719,24 @@ class TokenIndex implements HasTokenIndex, Immutable + self::TOKEN_INDEX; /** - * T_END_ALT_SYNTAX, T_OPEN_UNENCLOSED, T_CLOSE_UNENCLOSED + * T_CLOSE_ALT, T_OPEN_UNENCLOSED, T_CLOSE_UNENCLOSED * * @var array */ public array $Virtual = [ - \T_END_ALT_SYNTAX => true, + \T_CLOSE_ALT => true, \T_OPEN_UNENCLOSED => true, \T_CLOSE_UNENCLOSED => true, ] + self::TOKEN_INDEX; /** - * All (except T_END_ALT_SYNTAX, T_OPEN_UNENCLOSED, T_CLOSE_UNENCLOSED) + * All (except T_CLOSE_ALT, T_OPEN_UNENCLOSED, T_CLOSE_UNENCLOSED) * * @var array */ public array $NotVirtual = [ - \T_END_ALT_SYNTAX => false, + \T_CLOSE_ALT => false, \T_OPEN_UNENCLOSED => false, \T_CLOSE_UNENCLOSED => false, ] @@ -827,10 +788,9 @@ class TokenIndex implements HasTokenIndex, Immutable */ public array $BeforeAnonymousClassOrFunction = [ \T_NEW => true, - \T_ATTRIBUTE => true, - \T_ATTRIBUTE_COMMENT => true, \T_STATIC => true, ] + + self::ATTRIBUTE + self::TOKEN_INDEX; /** @@ -1107,22 +1067,6 @@ class TokenIndex implements HasTokenIndex, Immutable ] + self::TOKEN_INDEX; - // Parsing: - - /** - * Assignment operators, comparison operators (except T_COALESCE), - * T_DOUBLE_ARROW - * - * @var array - */ - public array $ExpressionDelimiter = [ - \T_DOUBLE_ARROW => true, - \T_COALESCE => false, - ] - + self::OPERATOR_ASSIGNMENT - + self::OPERATOR_COMPARISON - + self::TOKEN_INDEX; - /** * T_COLON, T_COMMA, T_SEMICOLON * diff --git a/tests/integration/Bootstrap/BootstrapTest.php b/tests/integration/Bootstrap/BootstrapTest.php index d5186d01..13000060 100644 --- a/tests/integration/Bootstrap/BootstrapTest.php +++ b/tests/integration/Bootstrap/BootstrapTest.php @@ -29,7 +29,7 @@ public static function bootstrapProvider(): array ? ['T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG', 'T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG'] : (\PHP_VERSION_ID < 80400 ? ['T_PROTECTED_SET', 'T_PRIVATE_SET'] - : ['T_END_ALT_SYNTAX', 'T_ATTRIBUTE_COMMENT'])); + : ['T_CLOSE_ALT', 'T_ATTRIBUTE_COMMENT'])); return [ [ diff --git a/tests/integration/Bootstrap/invalid-tokens.php b/tests/integration/Bootstrap/invalid-tokens.php index 22b61eb7..07f88592 100644 --- a/tests/integration/Bootstrap/invalid-tokens.php +++ b/tests/integration/Bootstrap/invalid-tokens.php @@ -15,7 +15,7 @@ defined('T_PUBLIC_SET') || define('T_PUBLIC_SET', 12); defined('T_PROPERTY_C') || define('T_PROPERTY_C', 13); defined('T_ATTRIBUTE_COMMENT') || define('T_ATTRIBUTE_COMMENT', 14); -defined('T_END_ALT_SYNTAX') || define('T_END_ALT_SYNTAX', 15); +defined('T_CLOSE_ALT') || define('T_CLOSE_ALT', 15); defined('T_NULL') || define('T_NULL', 16); defined('T_OPEN_UNENCLOSED') || define('T_OPEN_UNENCLOSED', 17); defined('T_CLOSE_UNENCLOSED') || define('T_CLOSE_UNENCLOSED', 18); diff --git a/tests/integration/Bootstrap/tokens-with-same-id.php b/tests/integration/Bootstrap/tokens-with-same-id.php index aded91b5..3fad2742 100644 --- a/tests/integration/Bootstrap/tokens-with-same-id.php +++ b/tests/integration/Bootstrap/tokens-with-same-id.php @@ -15,7 +15,7 @@ defined('T_PUBLIC_SET') || define('T_PUBLIC_SET', 10001); defined('T_PROPERTY_C') || define('T_PROPERTY_C', 10001); defined('T_ATTRIBUTE_COMMENT') || define('T_ATTRIBUTE_COMMENT', 10001); -defined('T_END_ALT_SYNTAX') || define('T_END_ALT_SYNTAX', 10001); +defined('T_CLOSE_ALT') || define('T_CLOSE_ALT', 10001); defined('T_NULL') || define('T_NULL', 10001); defined('T_OPEN_UNENCLOSED') || define('T_OPEN_UNENCLOSED', 10001); defined('T_CLOSE_UNENCLOSED') || define('T_CLOSE_UNENCLOSED', 10001); diff --git a/tests/unit/ParserTest.php b/tests/unit/ParserTest.php index 184a8f1d..98e88a6b 100644 --- a/tests/unit/ParserTest.php +++ b/tests/unit/ParserTest.php @@ -156,7 +156,7 @@ public static function parseProvider(): array 'Flags' => 'CODE', ], [ - 'id' => 'T_END_ALT_SYNTAX', + 'id' => 'T_CLOSE_ALT', 'text' => '', 'line' => 4, 'pos' => 36, @@ -192,7 +192,7 @@ public static function parseProvider(): array 'Flags' => 'CODE', ], [ - 'id' => 'T_END_ALT_SYNTAX', + 'id' => 'T_CLOSE_ALT', 'text' => '', 'line' => 5, 'pos' => 46, @@ -448,7 +448,7 @@ public static function parseProvider(): array 'Flags' => 'ONELINE_COMMENT|CPP_COMMENT', ], [ - 'id' => 'T_END_ALT_SYNTAX', + 'id' => 'T_CLOSE_ALT', 'text' => '', 'line' => 4, 'pos' => 72, @@ -492,7 +492,7 @@ public static function parseProvider(): array 'Flags' => 'ONELINE_COMMENT|CPP_COMMENT', ], [ - 'id' => 'T_END_ALT_SYNTAX', + 'id' => 'T_CLOSE_ALT', 'text' => '', 'line' => 5, 'pos' => 94, diff --git a/tests/unit/TokenIndexTest.php b/tests/unit/TokenIndexTest.php index 3bacde04..56359eca 100644 --- a/tests/unit/TokenIndexTest.php +++ b/tests/unit/TokenIndexTest.php @@ -164,9 +164,6 @@ public function testValues(): void $index = static::getIndex(); $properties = Reflect::getNames(static::getProperties()); foreach ($properties as $property) { - if (Str::startsWith($property, 'Alt')) { - continue; - } $value = $index->$property; if (is_array($value)) { ksort($value, \SORT_NUMERIC); @@ -201,7 +198,7 @@ public function testIndexes(ReflectionProperty $property, TokenIndex $index, str $this->assertSameSize(TokenIndex::TOKEN_INDEX, array_intersect_key($index->$name, TokenIndex::TOKEN_INDEX), 'Index must cover every token'); $this->assertEmpty(array_diff_key($index->$name, TokenIndex::TOKEN_INDEX), 'Index must only cover tokens'); $filtered = array_filter($index->$name); - if (Str::startsWith($name, ['Alt', 'AllowBlank', 'Suppress'])) { + if (Str::startsWith($name, ['Allow', 'Suppress'])) { $this->assertNotEmpty($filtered, 'Index cannot be empty'); return; } From 42788bc8ef30a43f747fb1a3bbed9b97253ff585 Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Tue, 7 Jan 2025 11:56:50 +1100 Subject: [PATCH 10/21] Reorganise `TokenIndex` so related indexes are grouped - No code changes --- src/TokenIndex.php | 120 ++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/src/TokenIndex.php b/src/TokenIndex.php index bf333f2f..a6244bd8 100644 --- a/src/TokenIndex.php +++ b/src/TokenIndex.php @@ -88,18 +88,6 @@ class TokenIndex implements HasTokenIndex, Immutable public array $OpenBracket = self::OPEN_BRACKET + self::TOKEN_INDEX; - /** - * T_OPEN_BRACE, T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_ATTRIBUTE, - * T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES, T_LOGICAL_NOT, T_NOT - * - * @var array - */ - public array $OpenBracketOrNot = self::OPEN_BRACKET + [ - \T_LOGICAL_NOT => true, - \T_NOT => true, - ] - + self::TOKEN_INDEX; - /** * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS * @@ -109,24 +97,14 @@ class TokenIndex implements HasTokenIndex, Immutable + self::TOKEN_INDEX; /** - * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_COMMA - * - * @var array - */ - public array $CloseBracketOrComma = self::CLOSE_BRACKET + [ - \T_COMMA => true, - ] - + self::TOKEN_INDEX; - - /** - * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_CLOSE_UNENCLOSED, - * T_CLOSE_ALT + * T_OPEN_BRACE, T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_ATTRIBUTE, + * T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES, T_LOGICAL_NOT, T_NOT * * @var array */ - public array $CloseBracketOrVirtual = self::CLOSE_BRACKET + [ - \T_CLOSE_UNENCLOSED => true, - \T_CLOSE_ALT => true, + public array $OpenBracketOrNot = self::OPEN_BRACKET + [ + \T_LOGICAL_NOT => true, + \T_NOT => true, ] + self::TOKEN_INDEX; @@ -188,6 +166,28 @@ class TokenIndex implements HasTokenIndex, Immutable ] + self::TOKEN_INDEX; + /** + * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_COMMA + * + * @var array + */ + public array $CloseBracketOrComma = self::CLOSE_BRACKET + [ + \T_COMMA => true, + ] + + self::TOKEN_INDEX; + + /** + * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_CLOSE_UNENCLOSED, + * T_CLOSE_ALT + * + * @var array + */ + public array $CloseBracketOrVirtual = self::CLOSE_BRACKET + [ + \T_CLOSE_UNENCLOSED => true, + \T_CLOSE_ALT => true, + ] + + self::TOKEN_INDEX; + /** * T_DECLARE, T_FOR, T_FOREACH, T_IF, T_ELSEIF, T_SWITCH, T_WHILE * @@ -397,6 +397,16 @@ class TokenIndex implements HasTokenIndex, Immutable + self::DECLARATION + self::TOKEN_INDEX; + /** + * Visibility modifiers, T_ABSTRACT, T_FINAL, T_READONLY, T_STATIC, T_VAR + * + * @var array + */ + public array $ModifierOrVar = self::MODIFIER + [ + \T_VAR => true, + ] + + self::TOKEN_INDEX; + /** * T_CLASS, T_ENUM, T_INTERFACE, T_TRAIT * @@ -441,22 +451,32 @@ class TokenIndex implements HasTokenIndex, Immutable + self::TOKEN_INDEX; /** - * T_FN, T_FUNCTION + * T_PRIVATE, T_PROTECTED, T_PUBLIC * * @var array */ - public array $FunctionOrFn = [ - \T_FN => true, - \T_FUNCTION => true, + public array $SymmetricVisibility = self::VISIBILITY_SYMMETRIC + + self::TOKEN_INDEX; + + /** + * Visibility modifiers, T_READONLY + * + * @var array + */ + public array $VisibilityOrReadonly = self::VISIBILITY + [ + \T_READONLY => true, ] + self::TOKEN_INDEX; /** - * T_PRIVATE, T_PROTECTED, T_PUBLIC + * T_FN, T_FUNCTION * * @var array */ - public array $SymmetricVisibility = self::VISIBILITY_SYMMETRIC + public array $FunctionOrFn = [ + \T_FN => true, + \T_FUNCTION => true, + ] + self::TOKEN_INDEX; /** @@ -494,16 +514,6 @@ class TokenIndex implements HasTokenIndex, Immutable ] + self::TOKEN_INDEX; - /** - * Visibility modifiers, T_ABSTRACT, T_FINAL, T_READONLY, T_STATIC, T_VAR - * - * @var array - */ - public array $ModifierOrVar = self::MODIFIER + [ - \T_VAR => true, - ] - + self::TOKEN_INDEX; - /** * T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG, T_COMMENT, T_DOC_COMMENT, * T_INLINE_HTML, T_WHITESPACE @@ -743,16 +753,6 @@ class TokenIndex implements HasTokenIndex, Immutable + self::ALL + self::TOKEN_INDEX; - /** - * Visibility modifiers, T_READONLY - * - * @var array - */ - public array $VisibilityOrReadonly = self::VISIBILITY + [ - \T_READONLY => true, - ] - + self::TOKEN_INDEX; - /** * T_WHITESPACE, T_BAD_CHARACTER * @@ -1055,27 +1055,27 @@ class TokenIndex implements HasTokenIndex, Immutable + self::TOKEN_INDEX; /** - * T_COLON, T_SEMICOLON, T_CLOSE_TAG, T_QUESTION + * T_COLON, T_COMMA, T_SEMICOLON * * @var array */ - public array $SwitchCaseDelimiterOrTernary = [ + public array $StatementDelimiter = [ \T_COLON => true, + \T_COMMA => true, \T_SEMICOLON => true, - \T_CLOSE_TAG => true, - \T_QUESTION => true, ] + self::TOKEN_INDEX; /** - * T_COLON, T_COMMA, T_SEMICOLON + * T_COLON, T_SEMICOLON, T_CLOSE_TAG, T_QUESTION * * @var array */ - public array $StatementDelimiter = [ + public array $SwitchCaseDelimiterOrTernary = [ \T_COLON => true, - \T_COMMA => true, \T_SEMICOLON => true, + \T_CLOSE_TAG => true, + \T_QUESTION => true, ] + self::TOKEN_INDEX; From bc5bb11aed84c449de1f37b9b9495b5160f8f435 Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Tue, 7 Jan 2025 12:35:21 +1100 Subject: [PATCH 11/21] Add `AbstractTokenIndex` and extend from `TokenIndex` This will allow custom indexes like `WordPressTokenIndex` to be decoupled from `TokenIndex` so new methods remain abstract until explicitly implemented. Without this change, methods added to `TokenIndex` are silently inherited by custom indexes, which may lead to unstable behaviour. --- src/AbstractTokenIndex.php | 1429 ++++++++++++++++++++++++++++++++++++ src/TokenIndex.php | 1406 +---------------------------------- 2 files changed, 1435 insertions(+), 1400 deletions(-) create mode 100644 src/AbstractTokenIndex.php diff --git a/src/AbstractTokenIndex.php b/src/AbstractTokenIndex.php new file mode 100644 index 00000000..c872bf96 --- /dev/null +++ b/src/AbstractTokenIndex.php @@ -0,0 +1,1429 @@ + + */ + protected const DEFAULT_ALLOW_NEWLINE_BEFORE = [ + \T_ATTRIBUTE => true, + \T_ATTRIBUTE_COMMENT => true, + \T_CLOSE_BRACKET => true, + \T_CLOSE_PARENTHESIS => true, + \T_CLOSE_TAG => true, + \T_COALESCE => true, + \T_CONCAT => true, + \T_DOUBLE_ARROW => true, + \T_LOGICAL_NOT => true, + \T_OBJECT_OPERATOR => true, + \T_NULLSAFE_OBJECT_OPERATOR => true, + ] + + self::OPERATOR_ARITHMETIC + + self::OPERATOR_BITWISE + + self::OPERATOR_TERNARY + + self::TOKEN_INDEX; + + /** + * @var array + */ + protected const DEFAULT_ALLOW_NEWLINE_AFTER = [ + \T_ATTRIBUTE => true, + \T_ATTRIBUTE_COMMENT => true, + \T_CLOSE_BRACE => true, + \T_COLON => true, + \T_COMMA => true, + \T_COMMENT => true, + \T_DOC_COMMENT => true, + \T_DOUBLE_ARROW => true, + \T_EXTENDS => true, + \T_IMPLEMENTS => true, + \T_OPEN_BRACE => true, + \T_OPEN_BRACKET => true, + \T_OPEN_PARENTHESIS => true, + \T_OPEN_TAG => true, + \T_OPEN_TAG_WITH_ECHO => true, + \T_SEMICOLON => true, + \T_COALESCE => false, + \T_LOGICAL_NOT => false, + ] + + self::OPERATOR_ASSIGNMENT + + self::OPERATOR_COMPARISON + + self::OPERATOR_LOGICAL + + self::TOKEN_INDEX; + + // Syntax: + + /** + * T_OPEN_BRACE, T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_CLOSE_BRACE, + * T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_ATTRIBUTE, T_CURLY_OPEN, + * T_DOLLAR_OPEN_CURLY_BRACES + * + * @var array + */ + public array $Bracket = self::OPEN_BRACKET + + self::CLOSE_BRACKET + + self::TOKEN_INDEX; + + /** + * T_OPEN_BRACE, T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_ATTRIBUTE, + * T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES + * + * @var array + */ + public array $OpenBracket = self::OPEN_BRACKET + + self::TOKEN_INDEX; + + /** + * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS + * + * @var array + */ + public array $CloseBracket = self::CLOSE_BRACKET + + self::TOKEN_INDEX; + + /** + * T_OPEN_BRACE, T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_ATTRIBUTE, + * T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES, T_LOGICAL_NOT, T_NOT + * + * @var array + */ + public array $OpenBracketOrNot = self::OPEN_BRACKET + [ + \T_LOGICAL_NOT => true, + \T_NOT => true, + ] + + self::TOKEN_INDEX; + + /** + * T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_ATTRIBUTE + * + * @var array + */ + public array $OpenBracketExceptBrace = [ + \T_OPEN_BRACE => false, + \T_CURLY_OPEN => false, + \T_DOLLAR_OPEN_CURLY_BRACES => false, + ] + + self::OPEN_BRACKET + + self::TOKEN_INDEX; + + /** + * T_OPEN_BRACE, T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES + * + * @var array + */ + public array $OpenBrace = [ + \T_OPEN_BRACE => true, + \T_CURLY_OPEN => true, + \T_DOLLAR_OPEN_CURLY_BRACES => true, + ] + + self::TOKEN_INDEX; + + /** + * T_OPEN_BRACE, T_IMPLEMENTS + * + * @var array + */ + public array $OpenBraceOrImplements = [ + \T_OPEN_BRACE => true, + \T_IMPLEMENTS => true, + ] + + self::TOKEN_INDEX; + + /** + * T_OPEN_BRACE, T_SEMICOLON + * + * @var array + */ + public array $OpenBraceOrSemicolon = [ + \T_OPEN_BRACE => true, + \T_SEMICOLON => true, + ] + + self::TOKEN_INDEX; + + /** + * T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO + * + * @var array + */ + public array $OpenTag = [ + \T_OPEN_TAG => true, + \T_OPEN_TAG_WITH_ECHO => true, + ] + + self::TOKEN_INDEX; + + /** + * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_COMMA + * + * @var array + */ + public array $CloseBracketOrComma = self::CLOSE_BRACKET + [ + \T_COMMA => true, + ] + + self::TOKEN_INDEX; + + /** + * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_CLOSE_UNENCLOSED, + * T_CLOSE_ALT + * + * @var array + */ + public array $CloseBracketOrVirtual = self::CLOSE_BRACKET + [ + \T_CLOSE_UNENCLOSED => true, + \T_CLOSE_ALT => true, + ] + + self::TOKEN_INDEX; + + /** + * T_DECLARE, T_FOR, T_FOREACH, T_IF, T_ELSEIF, T_SWITCH, T_WHILE + * + * @var array + */ + public array $AltStartOrContinue = [ + \T_DECLARE => true, + \T_FOR => true, + \T_FOREACH => true, + \T_IF => true, + \T_ELSEIF => true, + \T_SWITCH => true, + \T_WHILE => true, + ] + + self::TOKEN_INDEX; + + /** + * T_ELSEIF, T_ELSE, T_ENDDECLARE, T_ENDFOR, T_ENDFOREACH, T_ENDIF, + * T_ENDSWITCH, T_ENDWHILE + * + * @var array + */ + public array $AltContinueOrEnd = [ + \T_ELSEIF => true, + \T_ELSE => true, + \T_ENDDECLARE => true, + \T_ENDFOR => true, + \T_ENDFOREACH => true, + \T_ENDIF => true, + \T_ENDSWITCH => true, + \T_ENDWHILE => true, + ] + + self::TOKEN_INDEX; + + /** + * T_ENDDECLARE, T_ENDFOR, T_ENDFOREACH, T_ENDIF, T_ENDSWITCH, T_ENDWHILE + * + * @var array + */ + public array $AltEnd = [ + \T_ENDDECLARE => true, + \T_ENDFOR => true, + \T_ENDFOREACH => true, + \T_ENDIF => true, + \T_ENDSWITCH => true, + \T_ENDWHILE => true, + ] + + self::TOKEN_INDEX; + + /** + * T_AND, T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, + * T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG + * + * @var array + */ + public array $Ampersand = self::AMPERSAND + + self::TOKEN_INDEX; + + /** + * T_ATTRIBUTE, T_ATTRIBUTE_COMMENT + * + * @var array + */ + public array $Attribute = self::ATTRIBUTE + + self::TOKEN_INDEX; + + /** + * T_ATTRIBUTE, T_ATTRIBUTE_COMMENT, T_CASE, T_FUNCTION, T_NAMESPACE, T_USE, + * T_CONST, T_DECLARE, T_CLASS, T_ENUM, T_INTERFACE, T_TRAIT, T_ABSTRACT, + * T_FINAL, T_READONLY, T_STATIC, T_VAR, visibility modifiers + * + * @var array + */ + public array $AttributeOrDeclaration = self::ATTRIBUTE + + self::DECLARATION + + self::TOKEN_INDEX; + + /** + * T_ATTRIBUTE, T_ATTRIBUTE_COMMENT, T_ABSTRACT, T_FINAL, T_READONLY, + * T_STATIC, visibility modifiers + * + * @var array + */ + public array $AttributeOrModifier = self::ATTRIBUTE + + self::MODIFIER + + self::TOKEN_INDEX; + + /** + * T_ATTRIBUTE, T_ATTRIBUTE_COMMENT, T_STATIC + * + * @var array + */ + public array $AttributeOrStatic = self::ATTRIBUTE + [ + \T_STATIC => true, + ] + + self::TOKEN_INDEX; + + /** + * T_CASE, T_DEFAULT + * + * @var array + */ + public array $CaseOrDefault = [ + \T_CASE => true, + \T_DEFAULT => true, + ] + + self::TOKEN_INDEX; + + /** + * Casts + * + * @var array + */ + public array $Cast = self::CAST + + self::TOKEN_INDEX; + + /** + * T_CATCH, T_FINALLY + * + * @var array + */ + public array $CatchOrFinally = [ + \T_CATCH => true, + \T_FINALLY => true, + ] + + self::TOKEN_INDEX; + + /** + * T_OBJECT_OPERATOR, T_NULLSAFE_OBJECT_OPERATOR + * + * @var array + */ + public array $Chain = self::CHAIN + + self::TOKEN_INDEX; + + /** + * T_CLASS, T_FUNCTION + * + * @var array + */ + public array $ClassOrFunction = [ + \T_CLASS => true, + \T_FUNCTION => true, + ] + + self::TOKEN_INDEX; + + /** + * T_CONST, T_FUNCTION + * + * @var array + */ + public array $ConstOrFunction = [ + \T_CONST => true, + \T_FUNCTION => true, + ] + + self::TOKEN_INDEX; + + /** + * T_COMMA, T_DOUBLE_ARROW + * + * @var array + */ + public array $CommaOrDoubleArrow = [ + \T_COMMA => true, + \T_DOUBLE_ARROW => true, + ] + + self::TOKEN_INDEX; + + /** + * T_COMMENT, T_DOC_COMMENT + * + * @var array + */ + public array $Comment = self::COMMENT + + self::TOKEN_INDEX; + + /** + * T_COMMENT, T_DOC_COMMENT, T_SEMICOLON + * + * @var array + */ + public array $CommentOrSemicolon = self::COMMENT + [ + \T_SEMICOLON => true, + ] + + self::TOKEN_INDEX; + + /** + * T_ABSTRACT, T_CASE, T_CLASS, T_CONST, T_DECLARE, T_ENUM, T_FINAL, + * T_FUNCTION, T_INTERFACE, T_NAMESPACE, T_PRIVATE, T_PRIVATE_SET, + * T_PROTECTED, T_PROTECTED_SET, T_PUBLIC, T_PUBLIC_SET, T_READONLY, + * T_STATIC, T_TRAIT, T_USE, T_VAR + * + * @var array + */ + public array $Declaration = self::DECLARATION + + self::TOKEN_INDEX; + + /** + * T_CASE, T_CLASS, T_CONST, T_DECLARE, T_ENUM, T_FUNCTION, T_INTERFACE, + * T_NAMESPACE, T_TRAIT, T_USE + * + * @var array + */ + public array $DeclarationExceptModifierOrVar = self::NO_MODIFIER + [ + \T_VAR => false, + ] + + self::DECLARATION + + self::TOKEN_INDEX; + + /** + * Visibility modifiers, T_ABSTRACT, T_FINAL, T_READONLY, T_STATIC, T_VAR + * + * @var array + */ + public array $ModifierOrVar = self::MODIFIER + [ + \T_VAR => true, + ] + + self::TOKEN_INDEX; + + /** + * T_CLASS, T_ENUM, T_INTERFACE, T_TRAIT + * + * @var array + */ + public array $DeclarationClass = self::DECLARATION_CLASS + + self::TOKEN_INDEX; + + /** + * T_CLASS, T_ENUM, T_FUNCTION, T_INTERFACE, T_TRAIT + * + * @var array + */ + public array $DeclarationClassOrFunction = self::DECLARATION_CLASS + [ + \T_FUNCTION => true, + ] + + self::TOKEN_INDEX; + + /** + * T_CLASS, T_ENUM, T_FUNCTION, T_INTERFACE, T_NAMESPACE, T_TRAIT + * + * @var array + */ + public array $DeclarationTopLevel = [ + \T_FUNCTION => true, + \T_NAMESPACE => true, + ] + + self::DECLARATION_CLASS + + self::TOKEN_INDEX; + + /** + * Visibility modifiers, T_ABSTRACT, T_CONST, T_FINAL, T_READONLY, T_STATIC, + * T_VAR + * + * @var array + */ + public array $NonMethodMember = [ + \T_CONST => true, + \T_VAR => true, + ] + + self::MODIFIER + + self::TOKEN_INDEX; + + /** + * T_PRIVATE, T_PROTECTED, T_PUBLIC + * + * @var array + */ + public array $SymmetricVisibility = self::VISIBILITY_SYMMETRIC + + self::TOKEN_INDEX; + + /** + * Visibility modifiers, T_READONLY + * + * @var array + */ + public array $VisibilityOrReadonly = self::VISIBILITY + [ + \T_READONLY => true, + ] + + self::TOKEN_INDEX; + + /** + * T_FN, T_FUNCTION + * + * @var array + */ + public array $FunctionOrFn = [ + \T_FN => true, + \T_FUNCTION => true, + ] + + self::TOKEN_INDEX; + + /** + * T_IF, T_ELSEIF + * + * @var array + */ + public array $IfOrElseIf = [ + \T_IF => true, + \T_ELSEIF => true, + ] + + self::TOKEN_INDEX; + + /** + * T_ELSEIF, T_ELSE + * + * @var array + */ + public array $ElseIfOrElse = [ + \T_ELSEIF => true, + \T_ELSE => true, + ] + + self::TOKEN_INDEX; + + /** + * T_INLINE_HTML, T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG + * + * @var array + */ + public array $Markup = [ + \T_INLINE_HTML => true, + \T_OPEN_TAG => true, + \T_OPEN_TAG_WITH_ECHO => true, + \T_CLOSE_TAG => true, + ] + + self::TOKEN_INDEX; + + /** + * T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG, T_COMMENT, T_DOC_COMMENT, + * T_INLINE_HTML, T_WHITESPACE + * + * @var array + */ + public array $NotCode = [ + \T_INLINE_HTML => true, + \T_OPEN_TAG => true, + \T_OPEN_TAG_WITH_ECHO => true, + \T_CLOSE_TAG => true, + \T_WHITESPACE => true, + ] + + self::COMMENT + + self::TOKEN_INDEX; + + /** + * T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_INLINE_HTML + * + * @var array + */ + public array $OutsideCode = [ + \T_INLINE_HTML => true, + \T_OPEN_TAG => true, + \T_OPEN_TAG_WITH_ECHO => true, + ] + + self::TOKEN_INDEX; + + /** + * T_COMMENT, T_DOC_COMMENT, T_ATTRIBUTE_COMMENT, T_WHITESPACE + * + * @var array + */ + public array $NotCodeBeforeCloseTag = self::COMMENT + [ + \T_ATTRIBUTE_COMMENT => true, + \T_WHITESPACE => true, + ] + + self::TOKEN_INDEX; + + /** + * T_LNUMBER, T_DNUMBER + * + * @var array + */ + public array $Number = [ + \T_LNUMBER => true, + \T_DNUMBER => true, + ] + + self::TOKEN_INDEX; + + /** + * Arithmetic operators, assignment operators, bitwise operators, comparison + * operators, logical operators, ternary operators, T_AT, T_CONCAT, + * T_DOLLAR, T_DOUBLE_ARROW, T_INC, T_DEC, T_INSTANCEOF + * + * @var array + */ + public array $Operator = [ + \T_AT => true, + \T_CONCAT => true, + \T_DOLLAR => true, + \T_DOUBLE_ARROW => true, + \T_INC => true, + \T_DEC => true, + \T_INSTANCEOF => true, + ] + + self::OPERATOR_ARITHMETIC + + self::OPERATOR_ASSIGNMENT + + self::OPERATOR_BITWISE + + self::OPERATOR_COMPARISON + + self::OPERATOR_LOGICAL + + self::OPERATOR_TERNARY + + self::TOKEN_INDEX; + + /** + * Arithmetic operators, assignment operators, bitwise operators (except + * T_OR, T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG), comparison operators, + * logical operators, T_AT, T_CONCAT, T_DOLLAR, T_DOUBLE_ARROW, T_INC, + * T_DEC, T_INSTANCEOF + * + * @var array + */ + public array $OperatorExceptTernaryOrDelimiter = [ + \T_AT => true, + \T_CONCAT => true, + \T_DOLLAR => true, + \T_DOUBLE_ARROW => true, + \T_INC => true, + \T_DEC => true, + \T_INSTANCEOF => true, + \T_OR => false, + \T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG => false, + ] + + self::OPERATOR_ARITHMETIC + + self::OPERATOR_ASSIGNMENT + + self::OPERATOR_BITWISE + + self::OPERATOR_COMPARISON + + self::OPERATOR_LOGICAL + + self::TOKEN_INDEX; + + /** + * Assignment operators + * + * @var array + */ + public array $Assignment = self::OPERATOR_ASSIGNMENT + + self::TOKEN_INDEX; + + /** + * Assignment operators, T_DOUBLE_ARROW + * + * @var array + */ + public array $AssignmentOrDoubleArrow = [ + \T_DOUBLE_ARROW => true, + ] + + self::OPERATOR_ASSIGNMENT + + self::TOKEN_INDEX; + + /** + * T_AND, T_OR, T_XOR, T_BOOLEAN_AND, T_BOOLEAN_OR, T_LOGICAL_AND, + * T_LOGICAL_OR, T_LOGICAL_XOR, T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, + * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG + * + * Includes `&`, `|`, `^`, `&&`, `||`, `and`, `or` and `xor`. + * + * @var array + */ + public array $BooleanExceptNot = [ + \T_OR => true, + \T_XOR => true, + \T_LOGICAL_NOT => false, + ] + + self::OPERATOR_LOGICAL + + self::AMPERSAND + + self::TOKEN_INDEX; + + /** + * T_AT, T_DEC, T_DOLLAR, T_INC, T_LOGICAL_NOT, T_NOT + * + * @var array + */ + public array $Unary = [ + \T_AT => true, + \T_DOLLAR => true, + \T_INC => true, + \T_DEC => true, + \T_LOGICAL_NOT => true, + \T_NOT => true, + ] + + self::TOKEN_INDEX; + + /** + * T_PLUS, T_MINUS + * + * @var array + */ + public array $PlusOrMinus = [ + \T_PLUS => true, + \T_MINUS => true, + ] + + self::TOKEN_INDEX; + + /** + * T_RETURN, T_YIELD, T_YIELD_FROM + * + * @var array + */ + public array $ReturnOrYield = [ + \T_RETURN => true, + \T_YIELD => true, + \T_YIELD_FROM => true, + ] + + self::TOKEN_INDEX; + + /** + * T_DOUBLE_QUOTE, T_START_HEREDOC, T_END_HEREDOC, T_BACKTICK + * + * @var array + */ + public array $StringDelimiter = [ + \T_DOUBLE_QUOTE => true, + \T_START_HEREDOC => true, + \T_END_HEREDOC => true, + \T_BACKTICK => true, + ] + + self::TOKEN_INDEX; + + /** + * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, T_OR + * + * @var array + */ + public array $TypeDelimiter = [ + \T_OR => true, + \T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG => true, + ] + + self::TOKEN_INDEX; + + /** + * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, T_ARRAY, T_CALLABLE, + * T_CLOSE_PARENTHESIS, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, + * T_NAME_RELATIVE, T_OPEN_PARENTHESIS, T_OR, T_QUESTION, T_STATIC, T_STRING + * + * @var array + */ + public array $ValueType = [ + \T_OR => true, + \T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG => true, + \T_CLOSE_PARENTHESIS => true, + ] + + self::VALUE_TYPE_START + + self::TOKEN_INDEX; + + /** + * T_CLOSE_ALT, T_OPEN_UNENCLOSED, T_CLOSE_UNENCLOSED + * + * @var array + */ + public array $Virtual = [ + \T_CLOSE_ALT => true, + \T_OPEN_UNENCLOSED => true, + \T_CLOSE_UNENCLOSED => true, + ] + + self::TOKEN_INDEX; + + /** + * All (except T_CLOSE_ALT, T_OPEN_UNENCLOSED, T_CLOSE_UNENCLOSED) + * + * @var array + */ + public array $NotVirtual = [ + \T_CLOSE_ALT => false, + \T_OPEN_UNENCLOSED => false, + \T_CLOSE_UNENCLOSED => false, + ] + + self::ALL + + self::TOKEN_INDEX; + + /** + * T_WHITESPACE, T_BAD_CHARACTER + * + * @var array + */ + public array $Whitespace = [ + \T_WHITESPACE => true, + \T_BAD_CHARACTER => true, + ] + + self::TOKEN_INDEX; + + // Context: + + /** + * T_OPEN_BRACE, T_OPEN_PARENTHESIS, T_EXTENDS, T_IMPLEMENTS + * + * The token that appears after an anonymous `T_CLASS` or `T_FUNCTION`. + * + * @var array + */ + public array $AfterAnonymousClassOrFunction = [ + \T_OPEN_BRACE => true, + \T_OPEN_PARENTHESIS => true, + \T_EXTENDS => true, + \T_IMPLEMENTS => true, + ] + + self::TOKEN_INDEX; + + /** + * T_NEW, T_ATTRIBUTE, T_ATTRIBUTE_COMMENT, T_STATIC + * + * @var array + */ + public array $BeforeAnonymousClassOrFunction = [ + \T_NEW => true, + \T_STATIC => true, + ] + + self::ATTRIBUTE + + self::TOKEN_INDEX; + + /** + * T_ARRAY, T_CLASS, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, + * T_CONSTANT_ENCAPSED_STRING, T_DECLARE, T_DOUBLE_QUOTE, T_FN, T_FOR, + * T_FUNCTION, T_ISSET, T_LIST, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, + * T_NAME_RELATIVE, T_STATIC, T_STRING, T_UNSET, T_USE, T_VARIABLE + * + * Tokens that may appear before parentheses that enclose a delimited list. + * + * @var array + */ + public array $BeforeListParenthesis = [ + \T_ARRAY => true, + \T_CLASS => true, + \T_DECLARE => true, + \T_FN => true, + \T_FOR => true, + \T_FUNCTION => true, + \T_ISSET => true, + \T_LIST => true, + \T_STATIC => true, + \T_UNSET => true, + \T_USE => true, + \T_VARIABLE => true, + ] + + self::DEREFERENCEABLE_SCALAR_END + + self::NAME + + self::TOKEN_INDEX; + + /** + * Arithmetic operators, assignment operators, bitwise operators, comparison + * operators, logical operators, casts, keywords, T_AT, T_COMMA, T_CONCAT, + * T_DOLLAR_OPEN_CURLY_BRACES, T_DOUBLE_ARROW, T_ELLIPSIS, T_OPEN_BRACE, + * T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_SEMICOLON + * + * Tokens that may appear before unary operators. + * + * @var array + */ + public array $BeforeUnary = [ + \T_AT => true, + \T_COMMA => true, + \T_CONCAT => true, + \T_DOLLAR_OPEN_CURLY_BRACES => true, + \T_DOUBLE_ARROW => true, + \T_ELLIPSIS => true, + \T_OPEN_BRACE => true, + \T_OPEN_BRACKET => true, + \T_OPEN_PARENTHESIS => true, + \T_SEMICOLON => true, + ] + + self::OPERATOR_ARITHMETIC + + self::OPERATOR_ASSIGNMENT + + self::OPERATOR_BITWISE + + self::OPERATOR_COMPARISON + + self::OPERATOR_LOGICAL + + self::CAST + + self::KEYWORD + + self::TOKEN_INDEX; + + /** + * T_OBJECT_OPERATOR, T_NULLSAFE_OBJECT_OPERATOR, T_OPEN_BRACE, + * T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_DOLLAR, T_STRING, T_VARIABLE + * + * @var array + */ + public array $ChainPart = self::CHAIN_PART + + self::TOKEN_INDEX; + + /** + * T_ELSEIF, T_ELSE, T_CATCH, T_FINALLY + * + * Excludes `T_WHILE`, which only qualifies after `T_DO`. Check for this + * separately. + * + * @var array + */ + public array $ContinuesControlStructure = [ + \T_ELSEIF => true, + \T_ELSE => true, + \T_CATCH => true, + \T_FINALLY => true, + ] + + self::TOKEN_INDEX; + + /** + * T_COMMA, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE, + * T_STATIC, T_STRING + * + * @var array + */ + public array $DeclarationList = self::DECLARATION_LIST + + self::TOKEN_INDEX; + + /** + * T_ABSTRACT, T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, + * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, T_AND, T_ATTRIBUTE_COMMENT, + * T_ATTRIBUTE, T_CASE, T_CLASS, T_COMMA, T_CONST, T_DECLARE, T_ENUM, + * T_EXTENDS, T_FINAL, T_FUNCTION, T_IMPLEMENTS, T_INTERFACE, + * T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE, T_NAMESPACE, + * T_NS_SEPARATOR, T_PRIVATE, T_PRIVATE_SET, T_PROTECTED, T_PROTECTED_SET, + * T_PUBLIC, T_PUBLIC_SET, T_READONLY, T_STATIC, T_STRING, T_TRAIT, T_USE, + * T_VAR + * + * @var array + */ + public array $DeclarationPart = self::DECLARATION_PART + + self::TOKEN_INDEX; + + /** + * T_ABSTRACT, T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, + * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, T_AND, T_ATTRIBUTE_COMMENT, + * T_ATTRIBUTE, T_CASE, T_CLASS, T_COMMA, T_CONST, T_DECLARE, T_ENUM, + * T_EXTENDS, T_FINAL, T_FUNCTION, T_IMPLEMENTS, T_INTERFACE, + * T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE, T_NAMESPACE, + * T_NEW, T_NS_SEPARATOR, T_PRIVATE, T_PRIVATE_SET, T_PROTECTED, + * T_PROTECTED_SET, T_PUBLIC, T_PUBLIC_SET, T_READONLY, T_STATIC, T_STRING, + * T_TRAIT, T_USE, T_VAR + * + * @var array + */ + public array $DeclarationPartWithNew = self::DECLARATION_PART + [ + \T_NEW => true, + ] + + self::TOKEN_INDEX; + + /** + * T_ABSTRACT, T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, + * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, T_AND, T_ARRAY, T_ATTRIBUTE, + * T_ATTRIBUTE_COMMENT, T_CALLABLE, T_CASE, T_CLASS, T_CLOSE_BRACE, + * T_CLOSE_PARENTHESIS, T_COLON, T_COMMA, T_CONST, T_DECLARE, T_ENUM, + * T_EXTENDS, T_FINAL, T_FUNCTION, T_IMPLEMENTS, T_INTERFACE, T_NAMESPACE, + * T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE, T_NEW, + * T_NS_SEPARATOR, T_OPEN_BRACE, T_OPEN_PARENTHESIS, T_OR, T_PRIVATE, + * T_PRIVATE_SET, T_PROTECTED, T_PROTECTED_SET, T_PUBLIC, T_PUBLIC_SET, + * T_QUESTION, T_READONLY, T_STATIC, T_STRING, T_TRAIT, T_USE, T_VAR + * + * @var array + */ + public array $DeclarationPartWithNewAndBody = self::DECLARATION_PART + [ + \T_ARRAY => true, + \T_CALLABLE => true, + \T_COLON => true, + \T_NEW => true, + \T_OPEN_BRACE => true, + \T_CLOSE_BRACE => true, + \T_OPEN_PARENTHESIS => true, + \T_CLOSE_PARENTHESIS => true, + \T_OR => true, + \T_QUESTION => true, + ] + + self::TOKEN_INDEX; + + /** + * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, + * T_CONSTANT_ENCAPSED_STRING, T_DOUBLE_QUOTE, T_NAME_FULLY_QUALIFIED, + * T_NAME_QUALIFIED, T_NAME_RELATIVE, T_STRING, T_STRING_VARNAME, + * T_VARIABLE, T_CLASS_C, T_DIR, T_FILE, T_FUNC_C, T_LINE, T_METHOD_C, + * T_NS_C, T_PROPERTY_C, T_TRAIT_C + * + * @var array + */ + public array $EndOfDereferenceable = self::DEREFERENCEABLE_END + + self::TOKEN_INDEX; + + /** + * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_STRING, T_VARIABLE + * + * @var array + */ + public array $EndOfVariable = [ + \T_CLOSE_BRACE => true, + \T_CLOSE_BRACKET => true, + \T_CLOSE_PARENTHESIS => true, + \T_STRING => true, + \T_VARIABLE => true, + ] + + self::TOKEN_INDEX; + + /** + * T_AND, T_STRING, T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, + * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG + * + * @var array + */ + public array $FunctionIdentifier = [ + \T_STRING => true, + ] + + self::AMPERSAND + + self::TOKEN_INDEX; + + /** + * T_ELSEIF, T_FOR, T_FOREACH, T_IF, T_SWITCH, T_WHILE + * + * @var array + */ + public array $HasExpression = [ + \T_CATCH => false, + \T_DECLARE => false, + ] + + self::HAS_EXPRESSION_AND_STATEMENT_WITH_OPTIONAL_BRACES + + self::HAS_EXPRESSION_AND_STATEMENT_WITH_BRACES + + self::TOKEN_INDEX; + + /** + * T_CATCH, T_DECLARE, T_DO, T_ELSE, T_ELSEIF, T_FINALLY, T_FOR, T_FOREACH, + * T_IF, T_SWITCH, T_TRY, T_WHILE + * + * @var array + */ + public array $HasStatement = self::HAS_STATEMENT_WITH_OPTIONAL_BRACES + + self::HAS_EXPRESSION_AND_STATEMENT_WITH_OPTIONAL_BRACES + + self::HAS_STATEMENT_WITH_BRACES + + self::HAS_EXPRESSION_AND_STATEMENT_WITH_BRACES + + self::TOKEN_INDEX; + + /** + * T_DO, T_ELSE, T_ELSEIF, T_FOR, T_FOREACH, T_IF, T_WHILE + * + * @var array + */ + public array $HasOptionalBraces = self::HAS_STATEMENT_WITH_OPTIONAL_BRACES + + self::HAS_EXPRESSION_AND_STATEMENT_WITH_OPTIONAL_BRACES + + self::TOKEN_INDEX; + + /** + * T_ELSEIF, T_FOR, T_FOREACH, T_IF, T_WHILE + * + * @var array + */ + public array $HasOptionalBracesWithExpression = self::HAS_EXPRESSION_AND_STATEMENT_WITH_OPTIONAL_BRACES + + self::TOKEN_INDEX; + + /** + * T_DO, T_ELSE + * + * @var array + */ + public array $HasOptionalBracesWithNoExpression = self::HAS_STATEMENT_WITH_OPTIONAL_BRACES + + self::TOKEN_INDEX; + + /** + * T_DOUBLE_ARROW, T_OPEN_BRACE, T_SEMICOLON + * + * @var array + */ + public array $StartOfPropertyHookBody = [ + \T_DOUBLE_ARROW => true, + \T_OPEN_BRACE => true, + \T_SEMICOLON => true, + ] + + self::TOKEN_INDEX; + + /** + * T_ARRAY, T_CALLABLE, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, + * T_NAME_RELATIVE, T_OPEN_PARENTHESIS, T_QUESTION, T_STATIC, T_STRING + * + * @var array + */ + public array $StartOfValueType = self::VALUE_TYPE_START + + self::TOKEN_INDEX; + + /** + * T_COLON, T_COMMA, T_SEMICOLON + * + * @var array + */ + public array $StatementDelimiter = [ + \T_COLON => true, + \T_COMMA => true, + \T_SEMICOLON => true, + ] + + self::TOKEN_INDEX; + + /** + * T_COLON, T_SEMICOLON, T_CLOSE_TAG, T_QUESTION + * + * @var array + */ + public array $SwitchCaseDelimiterOrTernary = [ + \T_COLON => true, + \T_SEMICOLON => true, + \T_CLOSE_TAG => true, + \T_QUESTION => true, + ] + + self::TOKEN_INDEX; + + // Formatting: + + /** + * T_ENCAPSED_AND_WHITESPACE, T_INLINE_HTML, T_OPEN_TAG, + * T_OPEN_TAG_WITH_ECHO, T_END_HEREDOC + * + * @var array + */ + public array $NotLeftTrimmable = self::NOT_TRIMMABLE + + self::RIGHT_TRIMMABLE + + self::TOKEN_INDEX; + + /** + * T_ENCAPSED_AND_WHITESPACE, T_INLINE_HTML, T_CLOSE_TAG, T_START_HEREDOC + * + * @var array + */ + public array $NotRightTrimmable = self::NOT_TRIMMABLE + + self::LEFT_TRIMMABLE + + self::TOKEN_INDEX; + + /** + * T_CLOSE_TAG, T_START_HEREDOC + * + * @var array + */ + public array $LeftTrimmable = self::LEFT_TRIMMABLE + + self::TOKEN_INDEX; + + /** + * T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_END_HEREDOC + * + * @var array + */ + public array $RightTrimmable = self::RIGHT_TRIMMABLE + + self::TOKEN_INDEX; + + /** + * T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG, T_START_HEREDOC, + * T_END_HEREDOC, T_COMMENT, T_DOC_COMMENT, T_ATTRIBUTE_COMMENT, + * T_WHITESPACE + * + * Includes left- and right-trimmable tokens. + * + * @var array + */ + public array $Trimmable = [ + \T_ATTRIBUTE_COMMENT => true, + \T_WHITESPACE => true, + ] + + self::COMMENT + + self::LEFT_TRIMMABLE + + self::RIGHT_TRIMMABLE + + self::TOKEN_INDEX; + + /** + * Tokens that may appear after a newline + * + * @prettyphp-dynamic + * + * @var array + */ + public array $AllowNewlineBefore = self::DEFAULT_ALLOW_NEWLINE_BEFORE; + + /** + * Tokens that may appear before a newline + * + * @prettyphp-dynamic + * + * @var array + */ + public array $AllowNewlineAfter = self::DEFAULT_ALLOW_NEWLINE_AFTER; + + /** + * Tokens that may appear after a blank line + * + * @prettyphp-dynamic + * + * @var array + */ + public array $AllowBlankBefore = [ + \T_CLOSE_TAG => true, + ] + + self::TOKEN_INDEX; + + /** + * Tokens that may appear before a blank line + * + * @prettyphp-dynamic + * + * @var array + */ + public array $AllowBlankAfter = [ + \T_CLOSE_BRACE => true, + \T_COLON => true, + \T_COMMA => true, + \T_COMMENT => true, + \T_DOC_COMMENT => true, + \T_OPEN_TAG => true, + \T_OPEN_TAG_WITH_ECHO => true, + \T_SEMICOLON => true, + ] + + self::TOKEN_INDEX; + + /** + * T_AS, T_FUNCTION, T_INSTEADOF, T_USE + * + * Tokens that require a leading and trailing space. + * + * @var array + */ + public array $AddSpace = [ + \T_AS => true, + \T_FUNCTION => true, + \T_INSTEADOF => true, + \T_USE => true, + ] + + self::TOKEN_INDEX; + + /** + * T_ARRAY, T_CALLABLE, T_ELLIPSIS, T_EXTENDS, T_FN, T_GLOBAL, T_IMPLEMENTS, + * T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE, + * T_NS_SEPARATOR, T_STATIC, T_STRING, T_VARIABLE, T_ABSTRACT, T_CONST, + * T_DECLARE, T_FINAL, T_READONLY, T_VAR, T_CLASS, T_ENUM, T_INTERFACE, + * T_TRAIT, T_PRIVATE, T_PRIVATE_SET, T_PROTECTED, T_PROTECTED_SET, + * T_PUBLIC, T_PUBLIC_SET + * + * Tokens that require a leading space. + * + * @var array + */ + public array $AddSpaceBefore = [ + \T_ARRAY => true, + \T_CALLABLE => true, + \T_ELLIPSIS => true, + \T_EXTENDS => true, + \T_FN => true, + \T_GLOBAL => true, + \T_IMPLEMENTS => true, + \T_NAME_FULLY_QUALIFIED => true, + \T_NAME_QUALIFIED => true, + \T_NAME_RELATIVE => true, + \T_NS_SEPARATOR => true, + \T_STATIC => true, + \T_STRING => true, + \T_VARIABLE => true, + ] + + self::DECLARATION_ONLY + + self::TOKEN_INDEX; + + /** + * T_BREAK, T_CASE, T_CATCH, T_CLONE, T_CONTINUE, T_ECHO, T_ELSE, T_ELSEIF, + * T_FOR, T_FOREACH, T_GOTO, T_IF, T_INCLUDE, T_INCLUDE_ONCE, T_MATCH, + * T_NEW, T_PRINT, T_REQUIRE, T_REQUIRE_ONCE, T_RETURN, T_SWITCH, T_THROW, + * T_WHILE, T_YIELD, T_YIELD_FROM, casts + * + * Tokens that require a trailing space. + * + * @var array + */ + public array $AddSpaceAfter = [ + \T_BREAK => true, + \T_CASE => true, + \T_CATCH => true, + \T_CLONE => true, + \T_CONTINUE => true, + \T_ECHO => true, + \T_ELSE => true, + \T_ELSEIF => true, + \T_FOR => true, + \T_FOREACH => true, + \T_GOTO => true, + \T_IF => true, + \T_INCLUDE => true, + \T_INCLUDE_ONCE => true, + \T_MATCH => true, + \T_NEW => true, + \T_PRINT => true, + \T_REQUIRE => true, + \T_REQUIRE_ONCE => true, + \T_RETURN => true, + \T_SWITCH => true, + \T_THROW => true, + \T_WHILE => true, + \T_YIELD => true, + \T_YIELD_FROM => true, + ] + + self::CAST + + self::TOKEN_INDEX; + + /** + * T_NS_SEPARATOR + * + * Tokens that must not render with a leading space. + * + * @var array + */ + public array $SuppressSpaceBefore = [ + \T_NS_SEPARATOR => true, + ] + + self::TOKEN_INDEX; + + /** + * T_DOUBLE_COLON, T_ELLIPSIS, T_NS_SEPARATOR, T_OBJECT_OPERATOR, + * T_NULLSAFE_OBJECT_OPERATOR + * + * Tokens that must not render with a trailing space. + * + * @var array + */ + public array $SuppressSpaceAfter = [ + \T_DOUBLE_COLON => true, + \T_ELLIPSIS => true, + \T_NS_SEPARATOR => true, + \T_OBJECT_OPERATOR => true, + \T_NULLSAFE_OBJECT_OPERATOR => true, + ] + + self::TOKEN_INDEX; + + // Filtering: + + /** + * Casts, T_ATTRIBUTE_COMMENT, T_CONSTANT_ENCAPSED_STRING, + * T_ENCAPSED_AND_WHITESPACE, T_INLINE_HTML, T_OPEN_TAG, T_START_HEREDOC, + * T_END_HEREDOC, T_WHITESPACE, T_YIELD_FROM, T_COMMENT, T_DOC_COMMENT + * + * Tokens that may contain tab characters. + * + * @var array + */ + public array $Expandable = [ + \T_ATTRIBUTE_COMMENT => true, + \T_CONSTANT_ENCAPSED_STRING => true, + \T_ENCAPSED_AND_WHITESPACE => true, + \T_INLINE_HTML => true, + \T_OPEN_TAG => true, + \T_START_HEREDOC => true, + \T_END_HEREDOC => true, + \T_WHITESPACE => true, + \T_YIELD_FROM => true, + ] + + self::CAST + + self::COMMENT + + self::TOKEN_INDEX; + + /** + * Arithmetic operators, assignment operators, bitwise operators, comparison + * operators, logical operators, ternary operators, T_COMMA, T_CONCAT, + * T_DOUBLE_ARROW, T_SEMICOLON, T_OBJECT_OPERATOR, + * T_NULLSAFE_OBJECT_OPERATOR + * + * Tokens that may be swapped with adjacent comment tokens for correct + * placement. + * + * @var array + */ + public array $Movable = [ + \T_COMMA => true, + \T_CONCAT => true, + \T_DOUBLE_ARROW => true, + \T_SEMICOLON => true, + ] + + self::CHAIN + + self::OPERATOR_ARITHMETIC + + self::OPERATOR_ASSIGNMENT + + self::OPERATOR_BITWISE + + self::OPERATOR_COMPARISON + + self::OPERATOR_LOGICAL + + self::OPERATOR_TERNARY + + self::TOKEN_INDEX; + + /** + * @return static + */ + abstract public function withLeadingOperators(); + + /** + * @return static + */ + abstract public function withTrailingOperators(); + + /** + * @return static + */ + abstract public function withMixedOperators(); + + /** + * @return static + */ + abstract public function withoutPreserveNewline(); + + /** + * @return static + */ + abstract public function withPreserveNewline(); + + /** + * Get an index of every token in the given indexes + * + * @param array ...$indexes + * @return array + */ + final public static function merge(array ...$indexes): array + { + $index = self::TOKEN_INDEX; + foreach ($indexes as $idx) { + $index = array_filter($idx) + $index; + } + return $index; + } + + /** + * Get an index of every token in a given index that is not present in any + * of the others + * + * @param array $index + * @param array ...$indexes + * @return array + */ + final public static function diff(array $index, array ...$indexes): array + { + if (!$indexes) { + // @codeCoverageIgnoreStart + return $index + self::TOKEN_INDEX; + // @codeCoverageIgnoreEnd + } + $index = array_filter($index); + foreach ($indexes as $idx) { + $filtered[] = array_filter($idx); + } + return array_diff_key($index, ...$filtered) + self::TOKEN_INDEX; + } + + /** + * Get an index of every token in a given index that is present in all of + * the others + * + * @param array $index + * @param array ...$indexes + * @return array + */ + final public static function intersect(array $index, array ...$indexes): array + { + if (!$indexes) { + // @codeCoverageIgnoreStart + return $index + self::TOKEN_INDEX; + // @codeCoverageIgnoreEnd + } + $index = array_filter($index); + foreach ($indexes as $idx) { + $filtered[] = array_filter($idx); + } + return array_intersect_key($index, ...$filtered) + self::TOKEN_INDEX; + } +} diff --git a/src/TokenIndex.php b/src/TokenIndex.php index a6244bd8..abcd4bed 100644 --- a/src/TokenIndex.php +++ b/src/TokenIndex.php @@ -2,14 +2,12 @@ namespace Lkrms\PrettyPHP; -use Lkrms\PrettyPHP\Contract\HasTokenIndex; -use Salient\Contract\Core\Immutable; use Salient\Core\Concern\HasMutator; /** * @api */ -class TokenIndex implements HasTokenIndex, Immutable +class TokenIndex extends AbstractTokenIndex { use HasMutator; @@ -17,1339 +15,6 @@ class TokenIndex implements HasTokenIndex, Immutable protected const LAST = 1; protected const MIXED = 2; - /** - * @var array - */ - private const DEFAULT_ALLOW_NEWLINE_BEFORE = [ - \T_ATTRIBUTE => true, - \T_ATTRIBUTE_COMMENT => true, - \T_CLOSE_BRACKET => true, - \T_CLOSE_PARENTHESIS => true, - \T_CLOSE_TAG => true, - \T_COALESCE => true, - \T_CONCAT => true, - \T_DOUBLE_ARROW => true, - \T_LOGICAL_NOT => true, - \T_OBJECT_OPERATOR => true, - \T_NULLSAFE_OBJECT_OPERATOR => true, - ] - + self::OPERATOR_ARITHMETIC - + self::OPERATOR_BITWISE - + self::OPERATOR_TERNARY - + self::TOKEN_INDEX; - - /** - * @var array - */ - private const DEFAULT_ALLOW_NEWLINE_AFTER = [ - \T_ATTRIBUTE => true, - \T_ATTRIBUTE_COMMENT => true, - \T_CLOSE_BRACE => true, - \T_COLON => true, - \T_COMMA => true, - \T_COMMENT => true, - \T_DOC_COMMENT => true, - \T_DOUBLE_ARROW => true, - \T_EXTENDS => true, - \T_IMPLEMENTS => true, - \T_OPEN_BRACE => true, - \T_OPEN_BRACKET => true, - \T_OPEN_PARENTHESIS => true, - \T_OPEN_TAG => true, - \T_OPEN_TAG_WITH_ECHO => true, - \T_SEMICOLON => true, - \T_COALESCE => false, - \T_LOGICAL_NOT => false, - ] - + self::OPERATOR_ASSIGNMENT - + self::OPERATOR_COMPARISON - + self::OPERATOR_LOGICAL - + self::TOKEN_INDEX; - - // Syntax: - - /** - * T_OPEN_BRACE, T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_CLOSE_BRACE, - * T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_ATTRIBUTE, T_CURLY_OPEN, - * T_DOLLAR_OPEN_CURLY_BRACES - * - * @var array - */ - public array $Bracket = self::OPEN_BRACKET - + self::CLOSE_BRACKET - + self::TOKEN_INDEX; - - /** - * T_OPEN_BRACE, T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_ATTRIBUTE, - * T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES - * - * @var array - */ - public array $OpenBracket = self::OPEN_BRACKET - + self::TOKEN_INDEX; - - /** - * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS - * - * @var array - */ - public array $CloseBracket = self::CLOSE_BRACKET - + self::TOKEN_INDEX; - - /** - * T_OPEN_BRACE, T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_ATTRIBUTE, - * T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES, T_LOGICAL_NOT, T_NOT - * - * @var array - */ - public array $OpenBracketOrNot = self::OPEN_BRACKET + [ - \T_LOGICAL_NOT => true, - \T_NOT => true, - ] - + self::TOKEN_INDEX; - - /** - * T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_ATTRIBUTE - * - * @var array - */ - public array $OpenBracketExceptBrace = [ - \T_OPEN_BRACE => false, - \T_CURLY_OPEN => false, - \T_DOLLAR_OPEN_CURLY_BRACES => false, - ] - + self::OPEN_BRACKET - + self::TOKEN_INDEX; - - /** - * T_OPEN_BRACE, T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES - * - * @var array - */ - public array $OpenBrace = [ - \T_OPEN_BRACE => true, - \T_CURLY_OPEN => true, - \T_DOLLAR_OPEN_CURLY_BRACES => true, - ] - + self::TOKEN_INDEX; - - /** - * T_OPEN_BRACE, T_IMPLEMENTS - * - * @var array - */ - public array $OpenBraceOrImplements = [ - \T_OPEN_BRACE => true, - \T_IMPLEMENTS => true, - ] - + self::TOKEN_INDEX; - - /** - * T_OPEN_BRACE, T_SEMICOLON - * - * @var array - */ - public array $OpenBraceOrSemicolon = [ - \T_OPEN_BRACE => true, - \T_SEMICOLON => true, - ] - + self::TOKEN_INDEX; - - /** - * T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO - * - * @var array - */ - public array $OpenTag = [ - \T_OPEN_TAG => true, - \T_OPEN_TAG_WITH_ECHO => true, - ] - + self::TOKEN_INDEX; - - /** - * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_COMMA - * - * @var array - */ - public array $CloseBracketOrComma = self::CLOSE_BRACKET + [ - \T_COMMA => true, - ] - + self::TOKEN_INDEX; - - /** - * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_CLOSE_UNENCLOSED, - * T_CLOSE_ALT - * - * @var array - */ - public array $CloseBracketOrVirtual = self::CLOSE_BRACKET + [ - \T_CLOSE_UNENCLOSED => true, - \T_CLOSE_ALT => true, - ] - + self::TOKEN_INDEX; - - /** - * T_DECLARE, T_FOR, T_FOREACH, T_IF, T_ELSEIF, T_SWITCH, T_WHILE - * - * @var array - */ - public array $AltStartOrContinue = [ - \T_DECLARE => true, - \T_FOR => true, - \T_FOREACH => true, - \T_IF => true, - \T_ELSEIF => true, - \T_SWITCH => true, - \T_WHILE => true, - ] - + self::TOKEN_INDEX; - - /** - * T_ELSEIF, T_ELSE, T_ENDDECLARE, T_ENDFOR, T_ENDFOREACH, T_ENDIF, - * T_ENDSWITCH, T_ENDWHILE - * - * @var array - */ - public array $AltContinueOrEnd = [ - \T_ELSEIF => true, - \T_ELSE => true, - \T_ENDDECLARE => true, - \T_ENDFOR => true, - \T_ENDFOREACH => true, - \T_ENDIF => true, - \T_ENDSWITCH => true, - \T_ENDWHILE => true, - ] - + self::TOKEN_INDEX; - - /** - * T_ENDDECLARE, T_ENDFOR, T_ENDFOREACH, T_ENDIF, T_ENDSWITCH, T_ENDWHILE - * - * @var array - */ - public array $AltEnd = [ - \T_ENDDECLARE => true, - \T_ENDFOR => true, - \T_ENDFOREACH => true, - \T_ENDIF => true, - \T_ENDSWITCH => true, - \T_ENDWHILE => true, - ] - + self::TOKEN_INDEX; - - /** - * T_AND, T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, - * T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG - * - * @var array - */ - public array $Ampersand = self::AMPERSAND - + self::TOKEN_INDEX; - - /** - * T_ATTRIBUTE, T_ATTRIBUTE_COMMENT - * - * @var array - */ - public array $Attribute = self::ATTRIBUTE - + self::TOKEN_INDEX; - - /** - * T_ATTRIBUTE, T_ATTRIBUTE_COMMENT, T_CASE, T_FUNCTION, T_NAMESPACE, T_USE, - * T_CONST, T_DECLARE, T_CLASS, T_ENUM, T_INTERFACE, T_TRAIT, T_ABSTRACT, - * T_FINAL, T_READONLY, T_STATIC, T_VAR, visibility modifiers - * - * @var array - */ - public array $AttributeOrDeclaration = self::ATTRIBUTE - + self::DECLARATION - + self::TOKEN_INDEX; - - /** - * T_ATTRIBUTE, T_ATTRIBUTE_COMMENT, T_ABSTRACT, T_FINAL, T_READONLY, - * T_STATIC, visibility modifiers - * - * @var array - */ - public array $AttributeOrModifier = self::ATTRIBUTE - + self::MODIFIER - + self::TOKEN_INDEX; - - /** - * T_ATTRIBUTE, T_ATTRIBUTE_COMMENT, T_STATIC - * - * @var array - */ - public array $AttributeOrStatic = self::ATTRIBUTE + [ - \T_STATIC => true, - ] - + self::TOKEN_INDEX; - - /** - * T_CASE, T_DEFAULT - * - * @var array - */ - public array $CaseOrDefault = [ - \T_CASE => true, - \T_DEFAULT => true, - ] - + self::TOKEN_INDEX; - - /** - * Casts - * - * @var array - */ - public array $Cast = self::CAST - + self::TOKEN_INDEX; - - /** - * T_CATCH, T_FINALLY - * - * @var array - */ - public array $CatchOrFinally = [ - \T_CATCH => true, - \T_FINALLY => true, - ] - + self::TOKEN_INDEX; - - /** - * T_OBJECT_OPERATOR, T_NULLSAFE_OBJECT_OPERATOR - * - * @var array - */ - public array $Chain = self::CHAIN - + self::TOKEN_INDEX; - - /** - * T_CLASS, T_FUNCTION - * - * @var array - */ - public array $ClassOrFunction = [ - \T_CLASS => true, - \T_FUNCTION => true, - ] - + self::TOKEN_INDEX; - - /** - * T_CONST, T_FUNCTION - * - * @var array - */ - public array $ConstOrFunction = [ - \T_CONST => true, - \T_FUNCTION => true, - ] - + self::TOKEN_INDEX; - - /** - * T_COMMA, T_DOUBLE_ARROW - * - * @var array - */ - public array $CommaOrDoubleArrow = [ - \T_COMMA => true, - \T_DOUBLE_ARROW => true, - ] - + self::TOKEN_INDEX; - - /** - * T_COMMENT, T_DOC_COMMENT - * - * @var array - */ - public array $Comment = self::COMMENT - + self::TOKEN_INDEX; - - /** - * T_COMMENT, T_DOC_COMMENT, T_SEMICOLON - * - * @var array - */ - public array $CommentOrSemicolon = self::COMMENT + [ - \T_SEMICOLON => true, - ] - + self::TOKEN_INDEX; - - /** - * T_ABSTRACT, T_CASE, T_CLASS, T_CONST, T_DECLARE, T_ENUM, T_FINAL, - * T_FUNCTION, T_INTERFACE, T_NAMESPACE, T_PRIVATE, T_PRIVATE_SET, - * T_PROTECTED, T_PROTECTED_SET, T_PUBLIC, T_PUBLIC_SET, T_READONLY, - * T_STATIC, T_TRAIT, T_USE, T_VAR - * - * @var array - */ - public array $Declaration = self::DECLARATION - + self::TOKEN_INDEX; - - /** - * T_CASE, T_CLASS, T_CONST, T_DECLARE, T_ENUM, T_FUNCTION, T_INTERFACE, - * T_NAMESPACE, T_TRAIT, T_USE - * - * @var array - */ - public array $DeclarationExceptModifierOrVar = self::NO_MODIFIER + [ - \T_VAR => false, - ] - + self::DECLARATION - + self::TOKEN_INDEX; - - /** - * Visibility modifiers, T_ABSTRACT, T_FINAL, T_READONLY, T_STATIC, T_VAR - * - * @var array - */ - public array $ModifierOrVar = self::MODIFIER + [ - \T_VAR => true, - ] - + self::TOKEN_INDEX; - - /** - * T_CLASS, T_ENUM, T_INTERFACE, T_TRAIT - * - * @var array - */ - public array $DeclarationClass = self::DECLARATION_CLASS - + self::TOKEN_INDEX; - - /** - * T_CLASS, T_ENUM, T_FUNCTION, T_INTERFACE, T_TRAIT - * - * @var array - */ - public array $DeclarationClassOrFunction = self::DECLARATION_CLASS + [ - \T_FUNCTION => true, - ] - + self::TOKEN_INDEX; - - /** - * T_CLASS, T_ENUM, T_FUNCTION, T_INTERFACE, T_NAMESPACE, T_TRAIT - * - * @var array - */ - public array $DeclarationTopLevel = [ - \T_FUNCTION => true, - \T_NAMESPACE => true, - ] - + self::DECLARATION_CLASS - + self::TOKEN_INDEX; - - /** - * Visibility modifiers, T_ABSTRACT, T_CONST, T_FINAL, T_READONLY, T_STATIC, - * T_VAR - * - * @var array - */ - public array $NonMethodMember = [ - \T_CONST => true, - \T_VAR => true, - ] - + self::MODIFIER - + self::TOKEN_INDEX; - - /** - * T_PRIVATE, T_PROTECTED, T_PUBLIC - * - * @var array - */ - public array $SymmetricVisibility = self::VISIBILITY_SYMMETRIC - + self::TOKEN_INDEX; - - /** - * Visibility modifiers, T_READONLY - * - * @var array - */ - public array $VisibilityOrReadonly = self::VISIBILITY + [ - \T_READONLY => true, - ] - + self::TOKEN_INDEX; - - /** - * T_FN, T_FUNCTION - * - * @var array - */ - public array $FunctionOrFn = [ - \T_FN => true, - \T_FUNCTION => true, - ] - + self::TOKEN_INDEX; - - /** - * T_IF, T_ELSEIF - * - * @var array - */ - public array $IfOrElseIf = [ - \T_IF => true, - \T_ELSEIF => true, - ] - + self::TOKEN_INDEX; - - /** - * T_ELSEIF, T_ELSE - * - * @var array - */ - public array $ElseIfOrElse = [ - \T_ELSEIF => true, - \T_ELSE => true, - ] - + self::TOKEN_INDEX; - - /** - * T_INLINE_HTML, T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG - * - * @var array - */ - public array $Markup = [ - \T_INLINE_HTML => true, - \T_OPEN_TAG => true, - \T_OPEN_TAG_WITH_ECHO => true, - \T_CLOSE_TAG => true, - ] - + self::TOKEN_INDEX; - - /** - * T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG, T_COMMENT, T_DOC_COMMENT, - * T_INLINE_HTML, T_WHITESPACE - * - * @var array - */ - public array $NotCode = [ - \T_INLINE_HTML => true, - \T_OPEN_TAG => true, - \T_OPEN_TAG_WITH_ECHO => true, - \T_CLOSE_TAG => true, - \T_WHITESPACE => true, - ] - + self::COMMENT - + self::TOKEN_INDEX; - - /** - * T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_INLINE_HTML - * - * @var array - */ - public array $OutsideCode = [ - \T_INLINE_HTML => true, - \T_OPEN_TAG => true, - \T_OPEN_TAG_WITH_ECHO => true, - ] - + self::TOKEN_INDEX; - - /** - * T_COMMENT, T_DOC_COMMENT, T_ATTRIBUTE_COMMENT, T_WHITESPACE - * - * @var array - */ - public array $NotCodeBeforeCloseTag = self::COMMENT + [ - \T_ATTRIBUTE_COMMENT => true, - \T_WHITESPACE => true, - ] - + self::TOKEN_INDEX; - - /** - * T_LNUMBER, T_DNUMBER - * - * @var array - */ - public array $Number = [ - \T_LNUMBER => true, - \T_DNUMBER => true, - ] - + self::TOKEN_INDEX; - - /** - * Arithmetic operators, assignment operators, bitwise operators, comparison - * operators, logical operators, ternary operators, T_AT, T_CONCAT, - * T_DOLLAR, T_DOUBLE_ARROW, T_INC, T_DEC, T_INSTANCEOF - * - * @var array - */ - public array $Operator = [ - \T_AT => true, - \T_CONCAT => true, - \T_DOLLAR => true, - \T_DOUBLE_ARROW => true, - \T_INC => true, - \T_DEC => true, - \T_INSTANCEOF => true, - ] - + self::OPERATOR_ARITHMETIC - + self::OPERATOR_ASSIGNMENT - + self::OPERATOR_BITWISE - + self::OPERATOR_COMPARISON - + self::OPERATOR_LOGICAL - + self::OPERATOR_TERNARY - + self::TOKEN_INDEX; - - /** - * Arithmetic operators, assignment operators, bitwise operators (except - * T_OR, T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG), comparison operators, - * logical operators, T_AT, T_CONCAT, T_DOLLAR, T_DOUBLE_ARROW, T_INC, - * T_DEC, T_INSTANCEOF - * - * @var array - */ - public array $OperatorExceptTernaryOrDelimiter = [ - \T_AT => true, - \T_CONCAT => true, - \T_DOLLAR => true, - \T_DOUBLE_ARROW => true, - \T_INC => true, - \T_DEC => true, - \T_INSTANCEOF => true, - \T_OR => false, - \T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG => false, - ] - + self::OPERATOR_ARITHMETIC - + self::OPERATOR_ASSIGNMENT - + self::OPERATOR_BITWISE - + self::OPERATOR_COMPARISON - + self::OPERATOR_LOGICAL - + self::TOKEN_INDEX; - - /** - * Assignment operators - * - * @var array - */ - public array $Assignment = self::OPERATOR_ASSIGNMENT - + self::TOKEN_INDEX; - - /** - * Assignment operators, T_DOUBLE_ARROW - * - * @var array - */ - public array $AssignmentOrDoubleArrow = [ - \T_DOUBLE_ARROW => true, - ] - + self::OPERATOR_ASSIGNMENT - + self::TOKEN_INDEX; - - /** - * T_AND, T_OR, T_XOR, T_BOOLEAN_AND, T_BOOLEAN_OR, T_LOGICAL_AND, - * T_LOGICAL_OR, T_LOGICAL_XOR, T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, - * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG - * - * Includes `&`, `|`, `^`, `&&`, `||`, `and`, `or` and `xor`. - * - * @var array - */ - public array $BooleanExceptNot = [ - \T_OR => true, - \T_XOR => true, - \T_LOGICAL_NOT => false, - ] - + self::OPERATOR_LOGICAL - + self::AMPERSAND - + self::TOKEN_INDEX; - - /** - * T_AT, T_DEC, T_DOLLAR, T_INC, T_LOGICAL_NOT, T_NOT - * - * @var array - */ - public array $Unary = [ - \T_AT => true, - \T_DOLLAR => true, - \T_INC => true, - \T_DEC => true, - \T_LOGICAL_NOT => true, - \T_NOT => true, - ] - + self::TOKEN_INDEX; - - /** - * T_PLUS, T_MINUS - * - * @var array - */ - public array $PlusOrMinus = [ - \T_PLUS => true, - \T_MINUS => true, - ] - + self::TOKEN_INDEX; - - /** - * T_RETURN, T_YIELD, T_YIELD_FROM - * - * @var array - */ - public array $ReturnOrYield = [ - \T_RETURN => true, - \T_YIELD => true, - \T_YIELD_FROM => true, - ] - + self::TOKEN_INDEX; - - /** - * T_DOUBLE_QUOTE, T_START_HEREDOC, T_END_HEREDOC, T_BACKTICK - * - * @var array - */ - public array $StringDelimiter = [ - \T_DOUBLE_QUOTE => true, - \T_START_HEREDOC => true, - \T_END_HEREDOC => true, - \T_BACKTICK => true, - ] - + self::TOKEN_INDEX; - - /** - * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, T_OR - * - * @var array - */ - public array $TypeDelimiter = [ - \T_OR => true, - \T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG => true, - ] - + self::TOKEN_INDEX; - - /** - * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, T_ARRAY, T_CALLABLE, - * T_CLOSE_PARENTHESIS, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, - * T_NAME_RELATIVE, T_OPEN_PARENTHESIS, T_OR, T_QUESTION, T_STATIC, T_STRING - * - * @var array - */ - public array $ValueType = [ - \T_OR => true, - \T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG => true, - \T_CLOSE_PARENTHESIS => true, - ] - + self::VALUE_TYPE_START - + self::TOKEN_INDEX; - - /** - * T_CLOSE_ALT, T_OPEN_UNENCLOSED, T_CLOSE_UNENCLOSED - * - * @var array - */ - public array $Virtual = [ - \T_CLOSE_ALT => true, - \T_OPEN_UNENCLOSED => true, - \T_CLOSE_UNENCLOSED => true, - ] - + self::TOKEN_INDEX; - - /** - * All (except T_CLOSE_ALT, T_OPEN_UNENCLOSED, T_CLOSE_UNENCLOSED) - * - * @var array - */ - public array $NotVirtual = [ - \T_CLOSE_ALT => false, - \T_OPEN_UNENCLOSED => false, - \T_CLOSE_UNENCLOSED => false, - ] - + self::ALL - + self::TOKEN_INDEX; - - /** - * T_WHITESPACE, T_BAD_CHARACTER - * - * @var array - */ - public array $Whitespace = [ - \T_WHITESPACE => true, - \T_BAD_CHARACTER => true, - ] - + self::TOKEN_INDEX; - - // Context: - - /** - * T_OPEN_BRACE, T_OPEN_PARENTHESIS, T_EXTENDS, T_IMPLEMENTS - * - * The token that appears after an anonymous `T_CLASS` or `T_FUNCTION`. - * - * @var array - */ - public array $AfterAnonymousClassOrFunction = [ - \T_OPEN_BRACE => true, - \T_OPEN_PARENTHESIS => true, - \T_EXTENDS => true, - \T_IMPLEMENTS => true, - ] - + self::TOKEN_INDEX; - - /** - * T_NEW, T_ATTRIBUTE, T_ATTRIBUTE_COMMENT, T_STATIC - * - * @var array - */ - public array $BeforeAnonymousClassOrFunction = [ - \T_NEW => true, - \T_STATIC => true, - ] - + self::ATTRIBUTE - + self::TOKEN_INDEX; - - /** - * T_ARRAY, T_CLASS, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, - * T_CONSTANT_ENCAPSED_STRING, T_DECLARE, T_DOUBLE_QUOTE, T_FN, T_FOR, - * T_FUNCTION, T_ISSET, T_LIST, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, - * T_NAME_RELATIVE, T_STATIC, T_STRING, T_UNSET, T_USE, T_VARIABLE - * - * Tokens that may appear before parentheses that enclose a delimited list. - * - * @var array - */ - public array $BeforeListParenthesis = [ - \T_ARRAY => true, - \T_CLASS => true, - \T_DECLARE => true, - \T_FN => true, - \T_FOR => true, - \T_FUNCTION => true, - \T_ISSET => true, - \T_LIST => true, - \T_STATIC => true, - \T_UNSET => true, - \T_USE => true, - \T_VARIABLE => true, - ] - + self::DEREFERENCEABLE_SCALAR_END - + self::NAME - + self::TOKEN_INDEX; - - /** - * Arithmetic operators, assignment operators, bitwise operators, comparison - * operators, logical operators, casts, keywords, T_AT, T_COMMA, T_CONCAT, - * T_DOLLAR_OPEN_CURLY_BRACES, T_DOUBLE_ARROW, T_ELLIPSIS, T_OPEN_BRACE, - * T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_SEMICOLON - * - * Tokens that may appear before unary operators. - * - * @var array - */ - public array $BeforeUnary = [ - \T_AT => true, - \T_COMMA => true, - \T_CONCAT => true, - \T_DOLLAR_OPEN_CURLY_BRACES => true, - \T_DOUBLE_ARROW => true, - \T_ELLIPSIS => true, - \T_OPEN_BRACE => true, - \T_OPEN_BRACKET => true, - \T_OPEN_PARENTHESIS => true, - \T_SEMICOLON => true, - ] - + self::OPERATOR_ARITHMETIC - + self::OPERATOR_ASSIGNMENT - + self::OPERATOR_BITWISE - + self::OPERATOR_COMPARISON - + self::OPERATOR_LOGICAL - + self::CAST - + self::KEYWORD - + self::TOKEN_INDEX; - - /** - * T_OBJECT_OPERATOR, T_NULLSAFE_OBJECT_OPERATOR, T_OPEN_BRACE, - * T_OPEN_BRACKET, T_OPEN_PARENTHESIS, T_DOLLAR, T_STRING, T_VARIABLE - * - * @var array - */ - public array $ChainPart = self::CHAIN_PART - + self::TOKEN_INDEX; - - /** - * T_ELSEIF, T_ELSE, T_CATCH, T_FINALLY - * - * Excludes `T_WHILE`, which only qualifies after `T_DO`. Check for this - * separately. - * - * @var array - */ - public array $ContinuesControlStructure = [ - \T_ELSEIF => true, - \T_ELSE => true, - \T_CATCH => true, - \T_FINALLY => true, - ] - + self::TOKEN_INDEX; - - /** - * T_COMMA, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE, - * T_STATIC, T_STRING - * - * @var array - */ - public array $DeclarationList = self::DECLARATION_LIST - + self::TOKEN_INDEX; - - /** - * T_ABSTRACT, T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, - * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, T_AND, T_ATTRIBUTE_COMMENT, - * T_ATTRIBUTE, T_CASE, T_CLASS, T_COMMA, T_CONST, T_DECLARE, T_ENUM, - * T_EXTENDS, T_FINAL, T_FUNCTION, T_IMPLEMENTS, T_INTERFACE, - * T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE, T_NAMESPACE, - * T_NS_SEPARATOR, T_PRIVATE, T_PRIVATE_SET, T_PROTECTED, T_PROTECTED_SET, - * T_PUBLIC, T_PUBLIC_SET, T_READONLY, T_STATIC, T_STRING, T_TRAIT, T_USE, - * T_VAR - * - * @var array - */ - public array $DeclarationPart = self::DECLARATION_PART - + self::TOKEN_INDEX; - - /** - * T_ABSTRACT, T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, - * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, T_AND, T_ATTRIBUTE_COMMENT, - * T_ATTRIBUTE, T_CASE, T_CLASS, T_COMMA, T_CONST, T_DECLARE, T_ENUM, - * T_EXTENDS, T_FINAL, T_FUNCTION, T_IMPLEMENTS, T_INTERFACE, - * T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE, T_NAMESPACE, - * T_NEW, T_NS_SEPARATOR, T_PRIVATE, T_PRIVATE_SET, T_PROTECTED, - * T_PROTECTED_SET, T_PUBLIC, T_PUBLIC_SET, T_READONLY, T_STATIC, T_STRING, - * T_TRAIT, T_USE, T_VAR - * - * @var array - */ - public array $DeclarationPartWithNew = self::DECLARATION_PART + [ - \T_NEW => true, - ] - + self::TOKEN_INDEX; - - /** - * T_ABSTRACT, T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, - * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, T_AND, T_ARRAY, T_ATTRIBUTE, - * T_ATTRIBUTE_COMMENT, T_CALLABLE, T_CASE, T_CLASS, T_CLOSE_BRACE, - * T_CLOSE_PARENTHESIS, T_COLON, T_COMMA, T_CONST, T_DECLARE, T_ENUM, - * T_EXTENDS, T_FINAL, T_FUNCTION, T_IMPLEMENTS, T_INTERFACE, T_NAMESPACE, - * T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE, T_NEW, - * T_NS_SEPARATOR, T_OPEN_BRACE, T_OPEN_PARENTHESIS, T_OR, T_PRIVATE, - * T_PRIVATE_SET, T_PROTECTED, T_PROTECTED_SET, T_PUBLIC, T_PUBLIC_SET, - * T_QUESTION, T_READONLY, T_STATIC, T_STRING, T_TRAIT, T_USE, T_VAR - * - * @var array - */ - public array $DeclarationPartWithNewAndBody = self::DECLARATION_PART + [ - \T_ARRAY => true, - \T_CALLABLE => true, - \T_COLON => true, - \T_NEW => true, - \T_OPEN_BRACE => true, - \T_CLOSE_BRACE => true, - \T_OPEN_PARENTHESIS => true, - \T_CLOSE_PARENTHESIS => true, - \T_OR => true, - \T_QUESTION => true, - ] - + self::TOKEN_INDEX; - - /** - * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, - * T_CONSTANT_ENCAPSED_STRING, T_DOUBLE_QUOTE, T_NAME_FULLY_QUALIFIED, - * T_NAME_QUALIFIED, T_NAME_RELATIVE, T_STRING, T_STRING_VARNAME, - * T_VARIABLE, T_CLASS_C, T_DIR, T_FILE, T_FUNC_C, T_LINE, T_METHOD_C, - * T_NS_C, T_PROPERTY_C, T_TRAIT_C - * - * @var array - */ - public array $EndOfDereferenceable = self::DEREFERENCEABLE_END - + self::TOKEN_INDEX; - - /** - * T_CLOSE_BRACE, T_CLOSE_BRACKET, T_CLOSE_PARENTHESIS, T_STRING, T_VARIABLE - * - * @var array - */ - public array $EndOfVariable = [ - \T_CLOSE_BRACE => true, - \T_CLOSE_BRACKET => true, - \T_CLOSE_PARENTHESIS => true, - \T_STRING => true, - \T_VARIABLE => true, - ] - + self::TOKEN_INDEX; - - /** - * T_AND, T_STRING, T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, - * T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG - * - * @var array - */ - public array $FunctionIdentifier = [ - \T_STRING => true, - ] - + self::AMPERSAND - + self::TOKEN_INDEX; - - /** - * T_ELSEIF, T_FOR, T_FOREACH, T_IF, T_SWITCH, T_WHILE - * - * @var array - */ - public array $HasExpression = [ - \T_CATCH => false, - \T_DECLARE => false, - ] - + self::HAS_EXPRESSION_AND_STATEMENT_WITH_OPTIONAL_BRACES - + self::HAS_EXPRESSION_AND_STATEMENT_WITH_BRACES - + self::TOKEN_INDEX; - - /** - * T_CATCH, T_DECLARE, T_DO, T_ELSE, T_ELSEIF, T_FINALLY, T_FOR, T_FOREACH, - * T_IF, T_SWITCH, T_TRY, T_WHILE - * - * @var array - */ - public array $HasStatement = self::HAS_STATEMENT_WITH_OPTIONAL_BRACES - + self::HAS_EXPRESSION_AND_STATEMENT_WITH_OPTIONAL_BRACES - + self::HAS_STATEMENT_WITH_BRACES - + self::HAS_EXPRESSION_AND_STATEMENT_WITH_BRACES - + self::TOKEN_INDEX; - - /** - * T_DO, T_ELSE, T_ELSEIF, T_FOR, T_FOREACH, T_IF, T_WHILE - * - * @var array - */ - public array $HasOptionalBraces = self::HAS_STATEMENT_WITH_OPTIONAL_BRACES - + self::HAS_EXPRESSION_AND_STATEMENT_WITH_OPTIONAL_BRACES - + self::TOKEN_INDEX; - - /** - * T_ELSEIF, T_FOR, T_FOREACH, T_IF, T_WHILE - * - * @var array - */ - public array $HasOptionalBracesWithExpression = self::HAS_EXPRESSION_AND_STATEMENT_WITH_OPTIONAL_BRACES - + self::TOKEN_INDEX; - - /** - * T_DO, T_ELSE - * - * @var array - */ - public array $HasOptionalBracesWithNoExpression = self::HAS_STATEMENT_WITH_OPTIONAL_BRACES - + self::TOKEN_INDEX; - - /** - * T_DOUBLE_ARROW, T_OPEN_BRACE, T_SEMICOLON - * - * @var array - */ - public array $StartOfPropertyHookBody = [ - \T_DOUBLE_ARROW => true, - \T_OPEN_BRACE => true, - \T_SEMICOLON => true, - ] - + self::TOKEN_INDEX; - - /** - * T_ARRAY, T_CALLABLE, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, - * T_NAME_RELATIVE, T_OPEN_PARENTHESIS, T_QUESTION, T_STATIC, T_STRING - * - * @var array - */ - public array $StartOfValueType = self::VALUE_TYPE_START - + self::TOKEN_INDEX; - - /** - * T_COLON, T_COMMA, T_SEMICOLON - * - * @var array - */ - public array $StatementDelimiter = [ - \T_COLON => true, - \T_COMMA => true, - \T_SEMICOLON => true, - ] - + self::TOKEN_INDEX; - - /** - * T_COLON, T_SEMICOLON, T_CLOSE_TAG, T_QUESTION - * - * @var array - */ - public array $SwitchCaseDelimiterOrTernary = [ - \T_COLON => true, - \T_SEMICOLON => true, - \T_CLOSE_TAG => true, - \T_QUESTION => true, - ] - + self::TOKEN_INDEX; - - // Formatting: - - /** - * T_ENCAPSED_AND_WHITESPACE, T_INLINE_HTML, T_OPEN_TAG, - * T_OPEN_TAG_WITH_ECHO, T_END_HEREDOC - * - * @var array - */ - public array $NotLeftTrimmable = self::NOT_TRIMMABLE - + self::RIGHT_TRIMMABLE - + self::TOKEN_INDEX; - - /** - * T_ENCAPSED_AND_WHITESPACE, T_INLINE_HTML, T_CLOSE_TAG, T_START_HEREDOC - * - * @var array - */ - public array $NotRightTrimmable = self::NOT_TRIMMABLE - + self::LEFT_TRIMMABLE - + self::TOKEN_INDEX; - - /** - * T_CLOSE_TAG, T_START_HEREDOC - * - * @var array - */ - public array $LeftTrimmable = self::LEFT_TRIMMABLE - + self::TOKEN_INDEX; - - /** - * T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_END_HEREDOC - * - * @var array - */ - public array $RightTrimmable = self::RIGHT_TRIMMABLE - + self::TOKEN_INDEX; - - /** - * T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG, T_START_HEREDOC, - * T_END_HEREDOC, T_COMMENT, T_DOC_COMMENT, T_ATTRIBUTE_COMMENT, - * T_WHITESPACE - * - * Includes left- and right-trimmable tokens. - * - * @var array - */ - public array $Trimmable = [ - \T_ATTRIBUTE_COMMENT => true, - \T_WHITESPACE => true, - ] - + self::COMMENT - + self::LEFT_TRIMMABLE - + self::RIGHT_TRIMMABLE - + self::TOKEN_INDEX; - - /** - * Tokens that may appear after a newline - * - * @prettyphp-dynamic - * - * @var array - */ - public array $AllowNewlineBefore; - - /** - * Tokens that may appear before a newline - * - * @prettyphp-dynamic - * - * @var array - */ - public array $AllowNewlineAfter; - - /** - * Tokens that may appear after a blank line - * - * @prettyphp-dynamic - * - * @var array - */ - public array $AllowBlankBefore = [ - \T_CLOSE_TAG => true, - ] - + self::TOKEN_INDEX; - - /** - * Tokens that may appear before a blank line - * - * @prettyphp-dynamic - * - * @var array - */ - public array $AllowBlankAfter = [ - \T_CLOSE_BRACE => true, - \T_COLON => true, - \T_COMMA => true, - \T_COMMENT => true, - \T_DOC_COMMENT => true, - \T_OPEN_TAG => true, - \T_OPEN_TAG_WITH_ECHO => true, - \T_SEMICOLON => true, - ] - + self::TOKEN_INDEX; - - /** - * T_AS, T_FUNCTION, T_INSTEADOF, T_USE - * - * Tokens that require a leading and trailing space. - * - * @var array - */ - public array $AddSpace = [ - \T_AS => true, - \T_FUNCTION => true, - \T_INSTEADOF => true, - \T_USE => true, - ] - + self::TOKEN_INDEX; - - /** - * T_ARRAY, T_CALLABLE, T_ELLIPSIS, T_EXTENDS, T_FN, T_GLOBAL, T_IMPLEMENTS, - * T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE, - * T_NS_SEPARATOR, T_STATIC, T_STRING, T_VARIABLE, T_ABSTRACT, T_CONST, - * T_DECLARE, T_FINAL, T_READONLY, T_VAR, T_CLASS, T_ENUM, T_INTERFACE, - * T_TRAIT, T_PRIVATE, T_PRIVATE_SET, T_PROTECTED, T_PROTECTED_SET, - * T_PUBLIC, T_PUBLIC_SET - * - * Tokens that require a leading space. - * - * @var array - */ - public array $AddSpaceBefore = [ - \T_ARRAY => true, - \T_CALLABLE => true, - \T_ELLIPSIS => true, - \T_EXTENDS => true, - \T_FN => true, - \T_GLOBAL => true, - \T_IMPLEMENTS => true, - \T_NAME_FULLY_QUALIFIED => true, - \T_NAME_QUALIFIED => true, - \T_NAME_RELATIVE => true, - \T_NS_SEPARATOR => true, - \T_STATIC => true, - \T_STRING => true, - \T_VARIABLE => true, - ] - + self::DECLARATION_ONLY - + self::TOKEN_INDEX; - - /** - * T_BREAK, T_CASE, T_CATCH, T_CLONE, T_CONTINUE, T_ECHO, T_ELSE, T_ELSEIF, - * T_FOR, T_FOREACH, T_GOTO, T_IF, T_INCLUDE, T_INCLUDE_ONCE, T_MATCH, - * T_NEW, T_PRINT, T_REQUIRE, T_REQUIRE_ONCE, T_RETURN, T_SWITCH, T_THROW, - * T_WHILE, T_YIELD, T_YIELD_FROM, casts - * - * Tokens that require a trailing space. - * - * @var array - */ - public array $AddSpaceAfter = [ - \T_BREAK => true, - \T_CASE => true, - \T_CATCH => true, - \T_CLONE => true, - \T_CONTINUE => true, - \T_ECHO => true, - \T_ELSE => true, - \T_ELSEIF => true, - \T_FOR => true, - \T_FOREACH => true, - \T_GOTO => true, - \T_IF => true, - \T_INCLUDE => true, - \T_INCLUDE_ONCE => true, - \T_MATCH => true, - \T_NEW => true, - \T_PRINT => true, - \T_REQUIRE => true, - \T_REQUIRE_ONCE => true, - \T_RETURN => true, - \T_SWITCH => true, - \T_THROW => true, - \T_WHILE => true, - \T_YIELD => true, - \T_YIELD_FROM => true, - ] - + self::CAST - + self::TOKEN_INDEX; - - /** - * T_NS_SEPARATOR - * - * Tokens that must not render with a leading space. - * - * @var array - */ - public array $SuppressSpaceBefore = [ - \T_NS_SEPARATOR => true, - ] - + self::TOKEN_INDEX; - - /** - * T_DOUBLE_COLON, T_ELLIPSIS, T_NS_SEPARATOR, T_OBJECT_OPERATOR, - * T_NULLSAFE_OBJECT_OPERATOR - * - * Tokens that must not render with a trailing space. - * - * @var array - */ - public array $SuppressSpaceAfter = [ - \T_DOUBLE_COLON => true, - \T_ELLIPSIS => true, - \T_NS_SEPARATOR => true, - \T_OBJECT_OPERATOR => true, - \T_NULLSAFE_OBJECT_OPERATOR => true, - ] - + self::TOKEN_INDEX; - - // Filtering: - - /** - * Casts, T_ATTRIBUTE_COMMENT, T_CONSTANT_ENCAPSED_STRING, - * T_ENCAPSED_AND_WHITESPACE, T_INLINE_HTML, T_OPEN_TAG, T_START_HEREDOC, - * T_END_HEREDOC, T_WHITESPACE, T_YIELD_FROM, T_COMMENT, T_DOC_COMMENT - * - * Tokens that may contain tab characters. - * - * @var array - */ - public array $Expandable = [ - \T_ATTRIBUTE_COMMENT => true, - \T_CONSTANT_ENCAPSED_STRING => true, - \T_ENCAPSED_AND_WHITESPACE => true, - \T_INLINE_HTML => true, - \T_OPEN_TAG => true, - \T_START_HEREDOC => true, - \T_END_HEREDOC => true, - \T_WHITESPACE => true, - \T_YIELD_FROM => true, - ] - + self::CAST - + self::COMMENT - + self::TOKEN_INDEX; - - /** - * Arithmetic operators, assignment operators, bitwise operators, comparison - * operators, logical operators, ternary operators, T_COMMA, T_CONCAT, - * T_DOUBLE_ARROW, T_SEMICOLON, T_OBJECT_OPERATOR, - * T_NULLSAFE_OBJECT_OPERATOR - * - * Tokens that may be swapped with adjacent comment tokens for correct - * placement. - * - * @var array - */ - public array $Movable = [ - \T_COMMA => true, - \T_CONCAT => true, - \T_DOUBLE_ARROW => true, - \T_SEMICOLON => true, - ] - + self::CHAIN - + self::OPERATOR_ARITHMETIC - + self::OPERATOR_ASSIGNMENT - + self::OPERATOR_BITWISE - + self::OPERATOR_COMPARISON - + self::OPERATOR_LOGICAL - + self::OPERATOR_TERNARY - + self::TOKEN_INDEX; - /** @var self::FIRST|self::LAST|self::MIXED */ protected int $Operators; @@ -1373,7 +38,7 @@ public function __construct( } /** - * @return static + * @inheritDoc */ public function withLeadingOperators() { @@ -1409,7 +74,7 @@ private function getOperatorsFirstIndexes(): array } /** - * @return static + * @inheritDoc */ public function withTrailingOperators() { @@ -1449,7 +114,7 @@ private function getOperatorsLastIndexes(): array } /** - * @return static + * @inheritDoc */ public function withMixedOperators() { @@ -1459,7 +124,7 @@ public function withMixedOperators() } /** - * @return static + * @inheritDoc */ public function withoutPreserveNewline() { @@ -1468,7 +133,7 @@ public function withoutPreserveNewline() } /** - * @return static + * @inheritDoc */ public function withPreserveNewline() { @@ -1481,63 +146,4 @@ public function withPreserveNewline() return $this->withMixedOperators(); } } - - /** - * Get an index of every token in the given indexes - * - * @param array ...$indexes - * @return array - */ - final public static function merge(array ...$indexes): array - { - $index = self::TOKEN_INDEX; - foreach ($indexes as $idx) { - $index = array_filter($idx) + $index; - } - return $index; - } - - /** - * Get an index of every token in a given index that is not present in any - * of the others - * - * @param array $index - * @param array ...$indexes - * @return array - */ - final public static function diff(array $index, array ...$indexes): array - { - if (!$indexes) { - // @codeCoverageIgnoreStart - return $index + self::TOKEN_INDEX; - // @codeCoverageIgnoreEnd - } - $index = array_filter($index); - foreach ($indexes as $idx) { - $filtered[] = array_filter($idx); - } - return array_diff_key($index, ...$filtered) + self::TOKEN_INDEX; - } - - /** - * Get an index of every token in a given index that is present in all of - * the others - * - * @param array $index - * @param array ...$indexes - * @return array - */ - final public static function intersect(array $index, array ...$indexes): array - { - if (!$indexes) { - // @codeCoverageIgnoreStart - return $index + self::TOKEN_INDEX; - // @codeCoverageIgnoreEnd - } - $index = array_filter($index); - foreach ($indexes as $idx) { - $filtered[] = array_filter($idx); - } - return array_intersect_key($index, ...$filtered) + self::TOKEN_INDEX; - } } From bb93f92425a955ad5731cd40e9a3f8f295f13bde Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Tue, 7 Jan 2025 13:41:43 +1100 Subject: [PATCH 12/21] Accept `AbstractTokenIndex` in lieu of `TokenIndex` --- src/Concern/ExtensionTrait.php | 4 ++-- src/Concern/TokenRuleTrait.php | 4 ++-- src/Contract/TokenRule.php | 4 ++-- src/Filter/MoveComments.php | 5 ++--- src/Formatter.php | 6 +++--- src/FormatterBuilder.php | 2 +- src/Renderer.php | 2 +- src/Rule/AlignArrowFunctions.php | 4 ++-- src/Rule/AlignChains.php | 4 ++-- src/Rule/AlignTernaryOperators.php | 4 ++-- src/Rule/BlankBeforeReturn.php | 4 ++-- src/Rule/ControlStructureSpacing.php | 4 ++-- src/Rule/FormatHeredocs.php | 4 ++-- src/Rule/IndexSpacing.php | 6 +++--- src/Rule/NormaliseComments.php | 4 ++-- src/Rule/NormaliseNumbers.php | 4 ++-- src/Rule/NormaliseStrings.php | 4 ++-- src/Rule/OperatorSpacing.php | 4 ++-- src/Rule/PlaceBraces.php | 4 ++-- src/Rule/PlaceComments.php | 4 ++-- src/Rule/PreserveNewlines.php | 6 +++--- src/Rule/Preset/Drupal.php | 4 ++-- src/Rule/Preset/Laravel.php | 4 ++-- src/Rule/Preset/Symfony.php | 3 ++- src/Rule/Preset/WordPress.php | 4 ++-- src/Rule/ProtectStrings.php | 4 ++-- src/Rule/SemiStrictExpressions.php | 4 ++-- src/Rule/StandardSpacing.php | 6 +++--- src/Rule/StatementSpacing.php | 4 ++-- src/Rule/StrictExpressions.php | 4 ++-- src/Rule/SwitchIndentation.php | 4 ++-- src/Rule/VerticalSpacing.php | 6 +++--- src/Token.php | 2 +- tests/unit/Rule/Preset/Internal/WordPressTokenIndexTest.php | 2 +- tests/unit/TokenIndexTest.php | 5 +++-- 35 files changed, 72 insertions(+), 71 deletions(-) diff --git a/src/Concern/ExtensionTrait.php b/src/Concern/ExtensionTrait.php index 91395649..ad34c06d 100644 --- a/src/Concern/ExtensionTrait.php +++ b/src/Concern/ExtensionTrait.php @@ -3,8 +3,8 @@ namespace Lkrms\PrettyPHP\Concern; use Lkrms\PrettyPHP\Contract\Extension; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Formatter; -use Lkrms\PrettyPHP\TokenIndex; /** * @api @@ -14,7 +14,7 @@ trait ExtensionTrait { private Formatter $Formatter; - private TokenIndex $Idx; + private AbstractTokenIndex $Idx; public function __construct(Formatter $formatter) { diff --git a/src/Concern/TokenRuleTrait.php b/src/Concern/TokenRuleTrait.php index 48a90c79..9a0b063f 100644 --- a/src/Concern/TokenRuleTrait.php +++ b/src/Concern/TokenRuleTrait.php @@ -3,7 +3,7 @@ namespace Lkrms\PrettyPHP\Concern; use Lkrms\PrettyPHP\Contract\TokenRule; -use Lkrms\PrettyPHP\TokenIndex; +use Lkrms\PrettyPHP\AbstractTokenIndex; /** * @api @@ -17,7 +17,7 @@ trait TokenRuleTrait /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return ['*']; } diff --git a/src/Contract/TokenRule.php b/src/Contract/TokenRule.php index 6572f88f..58224717 100644 --- a/src/Contract/TokenRule.php +++ b/src/Contract/TokenRule.php @@ -2,8 +2,8 @@ namespace Lkrms\PrettyPHP\Contract; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * @api @@ -22,7 +22,7 @@ interface TokenRule extends Rule * * @return array|array{'*'} */ - public static function getTokens(TokenIndex $idx): array; + public static function getTokens(AbstractTokenIndex $idx): array; /** * Check if the rule requires tokens to be given in document order diff --git a/src/Filter/MoveComments.php b/src/Filter/MoveComments.php index a6ca30ba..ddfac8a1 100644 --- a/src/Filter/MoveComments.php +++ b/src/Filter/MoveComments.php @@ -5,7 +5,6 @@ use Lkrms\PrettyPHP\Concern\FilterTrait; use Lkrms\PrettyPHP\Contract\Filter; use Lkrms\PrettyPHP\GenericToken; -use Lkrms\PrettyPHP\TokenIndex; use Salient\Utility\Exception\ShouldNotHappenException; /** @@ -47,12 +46,12 @@ public function boot(): void { $idx = $this->Idx->withPreserveNewline(); - $this->BeforeCommentIndex = TokenIndex::intersect( + $this->BeforeCommentIndex = $this->Idx->intersect( $this->Idx->Movable, $idx->AllowNewlineAfter, ); - $this->AfterCommentIndex = TokenIndex::intersect( + $this->AfterCommentIndex = $this->Idx->intersect( $this->Idx->Movable, $idx->AllowNewlineBefore, ); diff --git a/src/Formatter.php b/src/Formatter.php index 76803fdd..dc27351a 100644 --- a/src/Formatter.php +++ b/src/Formatter.php @@ -127,7 +127,7 @@ final class Formatter implements Buildable, Immutable /** * Token index */ - public TokenIndex $TokenIndex; + public AbstractTokenIndex $TokenIndex; /** * End-of-line sequence used when line endings are not preserved or when @@ -476,7 +476,7 @@ final class Formatter implements Buildable, Immutable * @param array> $disable Non-mandatory extensions to disable * @param array> $enable Optional extensions to enable * @param int-mask-of $flags - * @param TokenIndex|null $tokenIndex Provide a customised token index + * @param AbstractTokenIndex|null $tokenIndex Provide a customised token index * @param HeredocIndent::* $heredocIndent * @param ImportSortOrder::* $importSortOrder */ @@ -486,7 +486,7 @@ public function __construct( array $disable = [], array $enable = [], int $flags = 0, - ?TokenIndex $tokenIndex = null, + ?AbstractTokenIndex $tokenIndex = null, string $preferredEol = \PHP_EOL, bool $preserveEol = true, int $spacesBesideCode = 2, diff --git a/src/FormatterBuilder.php b/src/FormatterBuilder.php index b9885fd3..dcb8c483 100644 --- a/src/FormatterBuilder.php +++ b/src/FormatterBuilder.php @@ -17,7 +17,7 @@ * @method $this disable(array> $value) Non-mandatory extensions to disable * @method $this enable(array> $value) Optional extensions to enable * @method $this flags(int-mask-of $value) Pass $value to `$flags` in Formatter::__construct() - * @method $this tokenIndex(TokenIndex|null $value) Provide a customised token index + * @method $this tokenIndex(AbstractTokenIndex|null $value) Provide a customised token index * @method $this preferredEol(string $value) End-of-line sequence used when line endings are not preserved or when there are no line breaks in the input * @method $this preserveEol(bool $value = true) True if line endings are preserved (default: true) * @method $this spacesBesideCode(int $value) Spaces between code and comments on the same line diff --git a/src/Renderer.php b/src/Renderer.php index c1e12b13..b2113603 100644 --- a/src/Renderer.php +++ b/src/Renderer.php @@ -20,7 +20,7 @@ final class Renderer implements Immutable private int $TabSize; private string $SoftTab; private string $Tab; - private TokenIndex $Idx; + private AbstractTokenIndex $Idx; public function __construct(Formatter $formatter) { diff --git a/src/Rule/AlignArrowFunctions.php b/src/Rule/AlignArrowFunctions.php index d84b2df6..0fdcd6da 100644 --- a/src/Rule/AlignArrowFunctions.php +++ b/src/Rule/AlignArrowFunctions.php @@ -5,8 +5,8 @@ use Lkrms\PrettyPHP\Catalog\TokenFlag; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * Align arrow function expressions with their definitions @@ -31,7 +31,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return [ \T_FN => true, diff --git a/src/Rule/AlignChains.php b/src/Rule/AlignChains.php index 4652ea75..0706e6b6 100644 --- a/src/Rule/AlignChains.php +++ b/src/Rule/AlignChains.php @@ -7,8 +7,8 @@ use Lkrms\PrettyPHP\Catalog\WhitespaceFlag as Space; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; use Lkrms\PrettyPHP\TokenUtil; /** @@ -34,7 +34,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return $idx->Chain; } diff --git a/src/Rule/AlignTernaryOperators.php b/src/Rule/AlignTernaryOperators.php index c5e49109..1f052b75 100644 --- a/src/Rule/AlignTernaryOperators.php +++ b/src/Rule/AlignTernaryOperators.php @@ -6,8 +6,8 @@ use Lkrms\PrettyPHP\Catalog\TokenFlag; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; use Lkrms\PrettyPHP\TokenUtil; /** @@ -33,7 +33,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return [ \T_QUESTION => true, diff --git a/src/Rule/BlankBeforeReturn.php b/src/Rule/BlankBeforeReturn.php index a354f7e1..11468a6d 100644 --- a/src/Rule/BlankBeforeReturn.php +++ b/src/Rule/BlankBeforeReturn.php @@ -5,7 +5,7 @@ use Lkrms\PrettyPHP\Catalog\TokenFlag; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; -use Lkrms\PrettyPHP\TokenIndex; +use Lkrms\PrettyPHP\AbstractTokenIndex; /** * Add blank lines before return statements @@ -29,7 +29,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return $idx->ReturnOrYield; } diff --git a/src/Rule/ControlStructureSpacing.php b/src/Rule/ControlStructureSpacing.php index 77e64299..841f7cbe 100644 --- a/src/Rule/ControlStructureSpacing.php +++ b/src/Rule/ControlStructureSpacing.php @@ -7,8 +7,8 @@ use Lkrms\PrettyPHP\Catalog\WhitespaceFlag as Space; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * Format control structures with unenclosed bodies @@ -32,7 +32,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return $idx->HasOptionalBraces; } diff --git a/src/Rule/FormatHeredocs.php b/src/Rule/FormatHeredocs.php index 887db76f..6d586b5f 100644 --- a/src/Rule/FormatHeredocs.php +++ b/src/Rule/FormatHeredocs.php @@ -5,8 +5,8 @@ use Lkrms\PrettyPHP\Catalog\HeredocIndent; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * Apply indentation to heredocs and nowdocs @@ -34,7 +34,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return [ \T_START_HEREDOC => true, diff --git a/src/Rule/IndexSpacing.php b/src/Rule/IndexSpacing.php index 7211df2a..f39a80cc 100644 --- a/src/Rule/IndexSpacing.php +++ b/src/Rule/IndexSpacing.php @@ -6,7 +6,7 @@ use Lkrms\PrettyPHP\Catalog\WhitespaceFlag as Space; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; -use Lkrms\PrettyPHP\TokenIndex; +use Lkrms\PrettyPHP\AbstractTokenIndex; /** * Apply whitespace to tokens as per the formatter's token index @@ -30,9 +30,9 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { - return TokenIndex::merge( + return $idx->merge( [ \T_COLON => true, \T_CLOSE_ALT => true, diff --git a/src/Rule/NormaliseComments.php b/src/Rule/NormaliseComments.php index 7f1f2a1f..f91a4988 100644 --- a/src/Rule/NormaliseComments.php +++ b/src/Rule/NormaliseComments.php @@ -8,8 +8,8 @@ use Lkrms\PrettyPHP\Catalog\TokenSubId; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; use Salient\Utility\Regex; /** @@ -34,7 +34,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return $idx->Comment; } diff --git a/src/Rule/NormaliseNumbers.php b/src/Rule/NormaliseNumbers.php index bcb18158..4ce88fd2 100644 --- a/src/Rule/NormaliseNumbers.php +++ b/src/Rule/NormaliseNumbers.php @@ -4,7 +4,7 @@ use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; -use Lkrms\PrettyPHP\TokenIndex; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Salient\Utility\Exception\ShouldNotHappenException; use Salient\Utility\Regex; use Salient\Utility\Str; @@ -31,7 +31,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return [ \T_LNUMBER => true, diff --git a/src/Rule/NormaliseStrings.php b/src/Rule/NormaliseStrings.php index cc20add1..c20370b0 100644 --- a/src/Rule/NormaliseStrings.php +++ b/src/Rule/NormaliseStrings.php @@ -5,8 +5,8 @@ use Lkrms\PrettyPHP\Catalog\TokenData; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; use Lkrms\PrettyPHP\TokenUtil; use Salient\Utility\Exception\ShouldNotHappenException; use Salient\Utility\Regex; @@ -36,7 +36,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return [ \T_CONSTANT_ENCAPSED_STRING => true, diff --git a/src/Rule/OperatorSpacing.php b/src/Rule/OperatorSpacing.php index 84b11c40..38c745d1 100644 --- a/src/Rule/OperatorSpacing.php +++ b/src/Rule/OperatorSpacing.php @@ -7,8 +7,8 @@ use Lkrms\PrettyPHP\Catalog\WhitespaceFlag as Space; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * Apply whitespace to operators @@ -32,7 +32,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return $idx->Operator; } diff --git a/src/Rule/PlaceBraces.php b/src/Rule/PlaceBraces.php index 64ac6aea..729d1268 100644 --- a/src/Rule/PlaceBraces.php +++ b/src/Rule/PlaceBraces.php @@ -6,8 +6,8 @@ use Lkrms\PrettyPHP\Catalog\WhitespaceFlag as Space; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * Apply whitespace to structural and match expression braces @@ -35,7 +35,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return [ \T_OPEN_BRACE => true, diff --git a/src/Rule/PlaceComments.php b/src/Rule/PlaceComments.php index cd11d2b6..729d22cd 100644 --- a/src/Rule/PlaceComments.php +++ b/src/Rule/PlaceComments.php @@ -8,8 +8,8 @@ use Lkrms\PrettyPHP\Catalog\WhitespaceFlag as Space; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * Place comments above or adjacent to code @@ -41,7 +41,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return $idx->Comment; } diff --git a/src/Rule/PreserveNewlines.php b/src/Rule/PreserveNewlines.php index fb15cd21..c191dce1 100644 --- a/src/Rule/PreserveNewlines.php +++ b/src/Rule/PreserveNewlines.php @@ -7,8 +7,8 @@ use Lkrms\PrettyPHP\Catalog\WhitespaceFlag as Space; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; use Lkrms\PrettyPHP\TokenUtil; /** @@ -36,7 +36,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return $idx->NotVirtual; } @@ -54,7 +54,7 @@ public static function needsSortedTokens(): bool */ public function boot(): void { - $this->AllowNewlineIndex = TokenIndex::merge( + $this->AllowNewlineIndex = $this->Idx->merge( $this->Idx->AllowNewlineBefore, $this->Idx->AllowNewlineAfter, ); diff --git a/src/Rule/Preset/Drupal.php b/src/Rule/Preset/Drupal.php index d018741f..ceecb2ce 100644 --- a/src/Rule/Preset/Drupal.php +++ b/src/Rule/Preset/Drupal.php @@ -10,9 +10,9 @@ use Lkrms\PrettyPHP\Contract\DeclarationRule; use Lkrms\PrettyPHP\Contract\Preset; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Formatter; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; use Salient\PHPDoc\PHPDoc; use Throwable; @@ -55,7 +55,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return [ \T_DOC_COMMENT => true, diff --git a/src/Rule/Preset/Laravel.php b/src/Rule/Preset/Laravel.php index 9ee3a1c4..8611ed9a 100644 --- a/src/Rule/Preset/Laravel.php +++ b/src/Rule/Preset/Laravel.php @@ -8,9 +8,9 @@ use Lkrms\PrettyPHP\Contract\Preset; use Lkrms\PrettyPHP\Contract\TokenRule; use Lkrms\PrettyPHP\Rule\BlankBeforeReturn; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Formatter; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * Apply the Laravel code style @@ -49,7 +49,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return [ \T_CONCAT => true, diff --git a/src/Rule/Preset/Symfony.php b/src/Rule/Preset/Symfony.php index f65420f5..4626a422 100644 --- a/src/Rule/Preset/Symfony.php +++ b/src/Rule/Preset/Symfony.php @@ -12,6 +12,7 @@ use Lkrms\PrettyPHP\Contract\TokenRule; use Lkrms\PrettyPHP\Internal\TokenCollection; use Lkrms\PrettyPHP\Rule\BlankBeforeReturn; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Formatter; use Lkrms\PrettyPHP\Token; use Lkrms\PrettyPHP\TokenIndex; @@ -59,7 +60,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return [ \T_CONCAT => true, diff --git a/src/Rule/Preset/WordPress.php b/src/Rule/Preset/WordPress.php index 890fd683..39bb43ce 100644 --- a/src/Rule/Preset/WordPress.php +++ b/src/Rule/Preset/WordPress.php @@ -10,9 +10,9 @@ use Lkrms\PrettyPHP\Rule\Preset\Internal\WordPressTokenIndex; use Lkrms\PrettyPHP\Rule\AlignData; use Lkrms\PrettyPHP\Rule\DeclarationSpacing; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Formatter; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * Apply the WordPress code style @@ -59,7 +59,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return [ \T_COMMENT => true, diff --git a/src/Rule/ProtectStrings.php b/src/Rule/ProtectStrings.php index 762e83fa..de042ccd 100644 --- a/src/Rule/ProtectStrings.php +++ b/src/Rule/ProtectStrings.php @@ -6,8 +6,8 @@ use Lkrms\PrettyPHP\Catalog\WhitespaceFlag as Space; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * Suppress changes to whitespace in strings and heredocs @@ -31,7 +31,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return [ \T_DOUBLE_QUOTE => true, diff --git a/src/Rule/SemiStrictExpressions.php b/src/Rule/SemiStrictExpressions.php index 8cdd57c4..7de8f571 100644 --- a/src/Rule/SemiStrictExpressions.php +++ b/src/Rule/SemiStrictExpressions.php @@ -5,8 +5,8 @@ use Lkrms\PrettyPHP\Catalog\WhitespaceFlag as Space; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * Add newlines before and after control structure expressions with newlines @@ -31,7 +31,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return $idx->HasExpression; } diff --git a/src/Rule/StandardSpacing.php b/src/Rule/StandardSpacing.php index 19a8d9d6..6997b447 100644 --- a/src/Rule/StandardSpacing.php +++ b/src/Rule/StandardSpacing.php @@ -10,8 +10,8 @@ use Lkrms\PrettyPHP\Contract\DeclarationRule; use Lkrms\PrettyPHP\Contract\TokenRule; use Lkrms\PrettyPHP\Internal\TokenCollection; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; use Lkrms\PrettyPHP\TokenUtil; use Salient\Utility\Regex; use Salient\Utility\Str; @@ -41,9 +41,9 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { - return TokenIndex::merge( + return $idx->merge( [ \T_CLOSE_TAG => true, \T_COMMA => true, diff --git a/src/Rule/StatementSpacing.php b/src/Rule/StatementSpacing.php index 195feeda..0074793d 100644 --- a/src/Rule/StatementSpacing.php +++ b/src/Rule/StatementSpacing.php @@ -5,8 +5,8 @@ use Lkrms\PrettyPHP\Catalog\WhitespaceFlag as Space; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * Apply whitespace to statement terminators @@ -30,7 +30,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return [ \T_COLON => true, diff --git a/src/Rule/StrictExpressions.php b/src/Rule/StrictExpressions.php index dae5cf42..db4ad39e 100644 --- a/src/Rule/StrictExpressions.php +++ b/src/Rule/StrictExpressions.php @@ -5,8 +5,8 @@ use Lkrms\PrettyPHP\Catalog\WhitespaceFlag as Space; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * Add newlines before and after control structure expressions that break over @@ -31,7 +31,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return $idx->HasExpression; } diff --git a/src/Rule/SwitchIndentation.php b/src/Rule/SwitchIndentation.php index 06f96cd9..ef2b9c15 100644 --- a/src/Rule/SwitchIndentation.php +++ b/src/Rule/SwitchIndentation.php @@ -5,8 +5,8 @@ use Lkrms\PrettyPHP\Catalog\WhitespaceFlag as Space; use Lkrms\PrettyPHP\Concern\TokenRuleTrait; use Lkrms\PrettyPHP\Contract\TokenRule; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; /** * Apply switch case list indentation @@ -30,7 +30,7 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { return [ \T_SWITCH => true, diff --git a/src/Rule/VerticalSpacing.php b/src/Rule/VerticalSpacing.php index a866a2cc..a81bc1e9 100644 --- a/src/Rule/VerticalSpacing.php +++ b/src/Rule/VerticalSpacing.php @@ -13,8 +13,8 @@ use Lkrms\PrettyPHP\Contract\ListRule; use Lkrms\PrettyPHP\Contract\TokenRule; use Lkrms\PrettyPHP\Internal\TokenCollection; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Lkrms\PrettyPHP\Token; -use Lkrms\PrettyPHP\TokenIndex; use Lkrms\PrettyPHP\TokenUtil; use Closure; @@ -53,9 +53,9 @@ public static function getPriority(string $method): ?int /** * @inheritDoc */ - public static function getTokens(TokenIndex $idx): array + public static function getTokens(AbstractTokenIndex $idx): array { - return TokenIndex::merge( + return $idx->merge( [ \T_FOR => true, \T_OPEN_BRACE => true, diff --git a/src/Token.php b/src/Token.php index 9905e13a..e2c9c29f 100644 --- a/src/Token.php +++ b/src/Token.php @@ -73,7 +73,7 @@ final class Token extends GenericToken implements HasTokenNames, JsonSerializabl public ?string $OriginalText = null; public Formatter $Formatter; - public TokenIndex $Idx; + public AbstractTokenIndex $Idx; public int $Whitespace = 0; public ?int $TagIndent = null; public int $PreIndent = 0; diff --git a/tests/unit/Rule/Preset/Internal/WordPressTokenIndexTest.php b/tests/unit/Rule/Preset/Internal/WordPressTokenIndexTest.php index e05a4434..144684aa 100644 --- a/tests/unit/Rule/Preset/Internal/WordPressTokenIndexTest.php +++ b/tests/unit/Rule/Preset/Internal/WordPressTokenIndexTest.php @@ -4,7 +4,7 @@ use Lkrms\PrettyPHP\Rule\Preset\Internal\WordPressTokenIndex; use Lkrms\PrettyPHP\Tests\TokenIndexTest; -use Lkrms\PrettyPHP\TokenIndex; +use Lkrms\PrettyPHP\AbstractTokenIndex as TokenIndex; final class WordPressTokenIndexTest extends TokenIndexTest { diff --git a/tests/unit/TokenIndexTest.php b/tests/unit/TokenIndexTest.php index 56359eca..2cad4bdc 100644 --- a/tests/unit/TokenIndexTest.php +++ b/tests/unit/TokenIndexTest.php @@ -2,7 +2,8 @@ namespace Lkrms\PrettyPHP\Tests; -use Lkrms\PrettyPHP\TokenIndex; +use Lkrms\PrettyPHP\AbstractTokenIndex as TokenIndex; +use Lkrms\PrettyPHP\TokenIndex as StandardTokenIndex; use Salient\PHPDoc\PHPDoc; use Salient\Utility\Exception\ShouldNotHappenException; use Salient\Utility\Arr; @@ -493,7 +494,7 @@ protected static function getProperties(): array protected static function getIndex(): TokenIndex { - return new TokenIndex(); + return new StandardTokenIndex(); } /** From d22210e68808c835c588502ca0b6d1f2105617b1 Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Tue, 7 Jan 2025 14:25:13 +1100 Subject: [PATCH 13/21] Finalise adoption of `AbstractTokenIndex` - Extend `AbstractTokenIndex` from `WordPressTokenIndex` - Make `TokenIndex` final --- src/AbstractTokenIndex.php | 54 ++++++++++++++++ .../Preset/Internal/WordPressTokenIndex.php | 38 ++++++----- src/TokenIndex.php | 64 ++----------------- 3 files changed, 82 insertions(+), 74 deletions(-) diff --git a/src/AbstractTokenIndex.php b/src/AbstractTokenIndex.php index c872bf96..22a1918f 100644 --- a/src/AbstractTokenIndex.php +++ b/src/AbstractTokenIndex.php @@ -1368,6 +1368,60 @@ abstract public function withoutPreserveNewline(); */ abstract public function withPreserveNewline(); + /** + * @return array{array,array} + */ + protected static function getOperatorsFirstIndexes(): array + { + $both = self::intersect( + self::DEFAULT_ALLOW_NEWLINE_BEFORE, + self::DEFAULT_ALLOW_NEWLINE_AFTER, + ); + + $before = self::OPERATOR_COMPARISON + + self::OPERATOR_LOGICAL + + self::DEFAULT_ALLOW_NEWLINE_BEFORE; + + $after = self::merge( + self::diff( + self::DEFAULT_ALLOW_NEWLINE_AFTER, + $before, + ), + $both + ); + + return [$before, $after]; + } + + /** + * @return array{array,array} + */ + protected static function getOperatorsLastIndexes(): array + { + $both = self::intersect( + self::DEFAULT_ALLOW_NEWLINE_BEFORE, + self::DEFAULT_ALLOW_NEWLINE_AFTER, + ); + + $after = [ + \T_COALESCE => true, + \T_CONCAT => true, + ] + + self::OPERATOR_ARITHMETIC + + self::OPERATOR_BITWISE + + self::DEFAULT_ALLOW_NEWLINE_AFTER; + + $before = self::merge( + self::diff( + self::DEFAULT_ALLOW_NEWLINE_BEFORE, + $after, + ), + $both + ); + + return [$before, $after]; + } + /** * Get an index of every token in the given indexes * diff --git a/src/Rule/Preset/Internal/WordPressTokenIndex.php b/src/Rule/Preset/Internal/WordPressTokenIndex.php index 7c145ab0..0666659c 100644 --- a/src/Rule/Preset/Internal/WordPressTokenIndex.php +++ b/src/Rule/Preset/Internal/WordPressTokenIndex.php @@ -2,33 +2,31 @@ namespace Lkrms\PrettyPHP\Rule\Preset\Internal; -use Lkrms\PrettyPHP\TokenIndex; +use Lkrms\PrettyPHP\AbstractTokenIndex; use Salient\Core\Concern\HasMutator; /** * @internal */ -final class WordPressTokenIndex extends TokenIndex +final class WordPressTokenIndex extends AbstractTokenIndex { use HasMutator; - /** @var array */ - private static array $DefaultAllowNewlineBefore; - /** @var array */ - private static array $DefaultAllowNewlineAfter; + private self $Original; public function __construct() { - parent::__construct(true); + [$before, $after] = self::getOperatorsFirstIndexes(); $this->AllowBlankBefore[\T_CLOSE_BRACE] = true; $this->AllowBlankAfter[\T_OPEN_BRACE] = true; - $this->AllowNewlineBefore[\T_CLOSE_BRACE] = true; - $this->AllowNewlineAfter[\T_OPEN_BRACE] = true; - $this->AllowNewlineAfter[\T_CONCAT] = true; + $before[\T_CLOSE_BRACE] = true; + $after[\T_OPEN_BRACE] = true; + $after[\T_CONCAT] = true; - self::$DefaultAllowNewlineBefore ??= $this->AllowNewlineBefore; - self::$DefaultAllowNewlineAfter ??= $this->AllowNewlineAfter; + $this->AllowNewlineBefore = $before; + $this->AllowNewlineAfter = $after; + $this->Original = $this; } /** @@ -55,10 +53,20 @@ public function withMixedOperators() return $this; } + /** + * @inheritDoc + */ + public function withoutPreserveNewline() + { + return $this->with('AllowNewlineBefore', $this->AllowBlankBefore) + ->with('AllowNewlineAfter', $this->AllowBlankAfter); + } + + /** + * @inheritDoc + */ public function withPreserveNewline() { - return $this->with('AllowNewlineBefore', self::$DefaultAllowNewlineBefore) - ->with('AllowNewlineAfter', self::$DefaultAllowNewlineAfter) - ->with('Operators', self::FIRST); + return $this->Original; } } diff --git a/src/TokenIndex.php b/src/TokenIndex.php index abcd4bed..1263d528 100644 --- a/src/TokenIndex.php +++ b/src/TokenIndex.php @@ -7,7 +7,7 @@ /** * @api */ -class TokenIndex extends AbstractTokenIndex +final class TokenIndex extends AbstractTokenIndex { use HasMutator; @@ -27,9 +27,9 @@ public function __construct( : ($operatorsLast ? self::LAST : self::MIXED); if ($operators === self::FIRST) { - [$before, $after] = $this->getOperatorsFirstIndexes(); + [$before, $after] = self::getOperatorsFirstIndexes(); } elseif ($operators === self::LAST) { - [$before, $after] = $this->getOperatorsLastIndexes(); + [$before, $after] = self::getOperatorsLastIndexes(); } $this->AllowNewlineBefore = $before ?? self::DEFAULT_ALLOW_NEWLINE_BEFORE; @@ -42,77 +42,23 @@ public function __construct( */ public function withLeadingOperators() { - [$before, $after] = $this->getOperatorsFirstIndexes(); + [$before, $after] = self::getOperatorsFirstIndexes(); return $this->with('AllowNewlineBefore', $before) ->with('AllowNewlineAfter', $after) ->with('Operators', self::FIRST); } - /** - * @return array{array,array} - */ - private function getOperatorsFirstIndexes(): array - { - $both = self::intersect( - self::DEFAULT_ALLOW_NEWLINE_BEFORE, - self::DEFAULT_ALLOW_NEWLINE_AFTER, - ); - - $before = self::OPERATOR_COMPARISON - + self::OPERATOR_LOGICAL - + self::DEFAULT_ALLOW_NEWLINE_BEFORE; - - $after = self::merge( - self::diff( - self::DEFAULT_ALLOW_NEWLINE_AFTER, - $before, - ), - $both - ); - - return [$before, $after]; - } - /** * @inheritDoc */ public function withTrailingOperators() { - [$before, $after] = $this->getOperatorsLastIndexes(); + [$before, $after] = self::getOperatorsLastIndexes(); return $this->with('AllowNewlineBefore', $before) ->with('AllowNewlineAfter', $after) ->with('Operators', self::LAST); } - /** - * @return array{array,array} - */ - private function getOperatorsLastIndexes(): array - { - $both = self::intersect( - self::DEFAULT_ALLOW_NEWLINE_BEFORE, - self::DEFAULT_ALLOW_NEWLINE_AFTER, - ); - - $after = [ - \T_COALESCE => true, - \T_CONCAT => true, - ] - + self::OPERATOR_ARITHMETIC - + self::OPERATOR_BITWISE - + self::DEFAULT_ALLOW_NEWLINE_AFTER; - - $before = self::merge( - self::diff( - self::DEFAULT_ALLOW_NEWLINE_BEFORE, - $after, - ), - $both - ); - - return [$before, $after]; - } - /** * @inheritDoc */ From a68e1578848547219bb1a5efaa41b42c1c9c9f0b Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Tue, 7 Jan 2025 15:07:09 +1100 Subject: [PATCH 14/21] Improve code coverage --- src/Rule/HangingIndentation.php | 3 +-- src/Rule/StandardIndentation.php | 2 +- tests/unit/Rule/HangingIndentationTest.php | 4 +++- tests/unit/TestCase.php | 6 +++++- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Rule/HangingIndentation.php b/src/Rule/HangingIndentation.php index 90c9f8e0..b0b17672 100644 --- a/src/Rule/HangingIndentation.php +++ b/src/Rule/HangingIndentation.php @@ -49,7 +49,7 @@ public static function getPriority(string $method): ?int } /** - * @inheritDoc + * @codeCoverageIgnore */ public static function needsSortedTokens(): bool { @@ -358,7 +358,6 @@ public function processTokens(array $tokens): void // context, followed by the precedence value added previously // - the token added to the last context, followed by the // precedence value added previously (if present) - // - `$lastToken` if no token was added to the last context if ( TokenUtil::OPERATOR_PRECEDENCE_INDEX[$trigger->id] && ($precedence = TokenUtil::getOperatorPrecedence($trigger)) < 99 diff --git a/src/Rule/StandardIndentation.php b/src/Rule/StandardIndentation.php index 6c38facc..5eab0937 100644 --- a/src/Rule/StandardIndentation.php +++ b/src/Rule/StandardIndentation.php @@ -26,7 +26,7 @@ public static function getPriority(string $method): ?int } /** - * @inheritDoc + * @codeCoverageIgnore */ public static function needsSortedTokens(): bool { diff --git a/tests/unit/Rule/HangingIndentationTest.php b/tests/unit/Rule/HangingIndentationTest.php index 05cb4ba1..5a23414c 100644 --- a/tests/unit/Rule/HangingIndentationTest.php +++ b/tests/unit/Rule/HangingIndentationTest.php @@ -2,6 +2,7 @@ namespace Lkrms\PrettyPHP\Tests\Rule; +use Lkrms\PrettyPHP\Catalog\FormatterFlag; use Lkrms\PrettyPHP\Rule\AlignChains; use Lkrms\PrettyPHP\Tests\TestCase; use Lkrms\PrettyPHP\Formatter; @@ -25,7 +26,8 @@ public function testOutput(string $expected, string $code, $formatter): void */ public static function outputProvider(): array { - $formatterB = Formatter::build(); + $formatterB = Formatter::build() + ->flags(FormatterFlag::DETECT_PROBLEMS); $formatter = $formatterB->build(); $withAlignChains = $formatterB ->enable([AlignChains::class]) diff --git a/tests/unit/TestCase.php b/tests/unit/TestCase.php index 01cfd059..161336b2 100644 --- a/tests/unit/TestCase.php +++ b/tests/unit/TestCase.php @@ -2,6 +2,7 @@ namespace Lkrms\PrettyPHP\Tests; +use Lkrms\PrettyPHP\Catalog\FormatterFlag; use Lkrms\PrettyPHP\Contract\Extension; use Lkrms\PrettyPHP\Contract\HasTokenNames; use Lkrms\PrettyPHP\Formatter; @@ -43,6 +44,7 @@ public static function assertFormatterOutputIs(string $expected, string $code, $ * @param array> $enable * @param array> $disable * @param 2|4|8 $tabSize + * @param int-mask-of $flags */ public static function assertCodeFormatIs( string $expected, @@ -50,7 +52,8 @@ public static function assertCodeFormatIs( array $enable = [], array $disable = [], bool $insertSpaces = true, - int $tabSize = 4 + int $tabSize = 4, + int $flags = FormatterFlag::DETECT_PROBLEMS ): void { self::assertFormatterOutputIs( $expected, @@ -60,6 +63,7 @@ public static function assertCodeFormatIs( ->tabSize($tabSize) ->enable($enable) ->disable($disable) + ->flags($flags) ); } From 818fdd243aede6c2de432834ffd8c41492bf918c Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Wed, 8 Jan 2025 15:50:46 +1100 Subject: [PATCH 15/21] Add `--no-problems` option to CLI command --- docs/Usage.md | 4 ++++ src/App/PrettyPHPCommand.php | 10 +++++++++- tests/unit/App/PrettyPHPCommandTest.php | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/Usage.md b/docs/Usage.md index 9589f8fe..d9fe5f14 100644 --- a/docs/Usage.md +++ b/docs/Usage.md @@ -263,6 +263,10 @@ pretty-php - Format a PHP file Report unchanged files. +- **`-R`**, **`--no-problems`** + + Do not report problems detected while formatting the input as warnings. + - **`-q`**, **`--quiet`** Do not report files that require formatting. diff --git a/src/App/PrettyPHPCommand.php b/src/App/PrettyPHPCommand.php index 9bdb9578..583dffc1 100644 --- a/src/App/PrettyPHPCommand.php +++ b/src/App/PrettyPHPCommand.php @@ -167,6 +167,7 @@ final class PrettyPHPCommand extends CliCommand private bool $ReportTimers = false; private bool $Fast = false; private bool $Verbose = false; + private bool $NoProblems = false; /** * - 0 = print unformatted files, summary, warnings, TTY-only progress @@ -600,6 +601,13 @@ protected function getOptionList(): iterable Report unchanged files. EOF) ->bindTo($this->Verbose), + CliOption::build() + ->long('no-problems') + ->short('R') + ->description(<<bindTo($this->NoProblems), CliOption::build() ->long('quiet') ->short('q') @@ -1550,7 +1558,7 @@ private function doGetFormatter(): Formatter $flags |= FormatterFlag::LOG_PROGRESS; } } - if ($this->Quiet < 3) { + if ($this->Quiet < 3 && !$this->NoProblems) { $flags |= FormatterFlag::DETECT_PROBLEMS; } diff --git a/tests/unit/App/PrettyPHPCommandTest.php b/tests/unit/App/PrettyPHPCommandTest.php index 433438b8..4f06f408 100644 --- a/tests/unit/App/PrettyPHPCommandTest.php +++ b/tests/unit/App/PrettyPHPCommandTest.php @@ -35,7 +35,7 @@ final class PrettyPHPCommandTest extends TestCase private const SYNOPSIS = <<<'EOF' -pretty-php [-1OLTNSnMbvq] [-I ] [-X ] [-P[]] +pretty-php [-1OLTNSnMbvRq] [-I ] [-X ] [-P[]] [-i ,...] [-r ,...] [-h ] [-m ] [--psr12] [-c ] [--no-config] [-o ,...] [--diff[=]] [--check] [--print-config] [--] [...] From b18ced5a09f4d003ac3fad495b1c60b245b93894 Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Tue, 7 Jan 2025 20:20:49 +1100 Subject: [PATCH 16/21] Report changes to output vs. latest release in CI integration tests --- .github/workflows/ci.yml | 62 +++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index acb1d39c..da285159 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -314,7 +314,6 @@ jobs: needs: - check-ci-runs - build - - test-phar if: ${{ (github.event_name == 'workflow_call' || needs.check-ci-runs.outputs.ci_required == 1) && !cancelled() && !failure() }} strategy: @@ -322,15 +321,20 @@ jobs: matrix: repository: - laravel/framework - args: + config: - --include-if-php --preset laravel src tests bin + args: + - --quiet --timers include: - repository: drupal/drupal - args: --exclude '/\/(\.git|\.hg|\.svn|_?build|dist|vendor|core\/lib\/Drupal\/Component\/Transliteration\/data)\/$/' --include-if-php=/./ --preset drupal . + config: --exclude '/\/(\.git|\.hg|\.svn|_?build|dist|vendor|core\/lib\/Drupal\/Component\/Transliteration\/data)\/$/' --include-if-php=/./ --preset drupal . + args: --quiet --timers - repository: symfony/symfony - args: --include-if-php --preset symfony . + config: --include-if-php --preset symfony . + args: --quiet --timers - repository: WordPress/WordPress - args: --include-if-php --preset wordpress . + config: --include-if-php --preset wordpress . + args: --quiet --timers --no-problems runs-on: ubuntu-latest @@ -344,10 +348,54 @@ jobs: uses: actions/download-artifact@v4 with: name: ${{ needs.build.outputs.artifact_name }} + path: ~/ - name: Run pretty-php + id: run-pretty-php + shell: bash env: artifact_path: ${{ needs.build.outputs.artifact_path }} + repository: ${{ matrix.repository }} run: | - php "$artifact_path" --print-config ${{ matrix.args }} | tee .prettyphp - php "$artifact_path" --quiet --timers || { status=$? && [[ $status -eq 4 ]] || (exit $status); } + check_status() { + local s=$? + ((s == 4)) || return $s + } + + set -o pipefail + shopt -s dotglob extglob + + artifact_path=~/$artifact_path + php "$artifact_path" --print-config ${{ matrix.config }} | tee .prettyphp + php "$artifact_path" ${{ matrix.args }} || check_status + + echo + echo "Downloading latest release to format $repository for comparison" + latest_path=~/pretty-php-latest.phar + latest_url=https://github.com/lkrms/pretty-php/releases/latest/download/pretty-php.phar + diff_path=~/${repository%/*}.diff + : >"$diff_path" + + # Stage changes in the background + git add !(.prettyphp) & + # Download latest release in the foreground + curl -fLo "$latest_path" "$latest_url" && + # Wait for background command to finish + wait $! && + # Keep index and restore working tree to HEAD + git restore -s HEAD . && + { php "$latest_path" --fast ${{ matrix.args }} || check_status; } && + echo && + # Swap inputs so diff is from working tree to index + git diff -U5 -R --exit-code | tee "$diff_path" && + echo "No differences found" || true + + printf 'diff_name=%s\n' "${diff_path##*/}" >>"$GITHUB_OUTPUT" + printf 'diff_path=%s\n' "$([[ ! -s $diff_path ]] || printf '%s\n' "$diff_path")" >>"$GITHUB_OUTPUT" + + - name: Upload diff artifact + if: ${{ !cancelled() && !failure() && steps.run-pretty-php.outputs.diff_path != '' }} + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.run-pretty-php.outputs.diff_name }} + path: ${{ steps.run-pretty-php.outputs.diff_path }} From e8a8cb28017aebdbff1255eba0df70a7ba1104b4 Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Wed, 8 Jan 2025 00:14:36 +1100 Subject: [PATCH 17/21] Update workflows to use ubuntu-24.04 instead of ubuntu-latest --- .github/workflows/ci.yml | 34 ++++++++++++++--------------- .github/workflows/documentation.yml | 4 ++-- .github/workflows/gc.yml | 2 +- .github/workflows/publish.yml | 6 ++--- .github/workflows/release.yml | 4 ++-- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da285159..591ed9f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: check-ci-runs: name: Check previous runs if: ${{ github.event_name != 'workflow_call' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: ci_required: ${{ steps.check-ci-runs.outputs.ci_required }} steps: @@ -34,7 +34,7 @@ jobs: needs: - check-ci-runs if: ${{ (github.event_name == 'workflow_call' || needs.check-ci-runs.outputs.ci_required == 1) && !cancelled() && !failure() }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout @@ -77,7 +77,7 @@ jobs: - "8.4" - "7.4" - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout @@ -124,21 +124,21 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest + - ubuntu-24.04 - windows-latest - macos-latest php-version: - "8.4" include: - - os: ubuntu-latest + - os: ubuntu-24.04 php-version: "8.3" - - os: ubuntu-latest + - os: ubuntu-24.04 php-version: "8.2" - - os: ubuntu-latest + - os: ubuntu-24.04 php-version: "8.1" - - os: ubuntu-latest + - os: ubuntu-24.04 php-version: "8.0" - - os: ubuntu-latest + - os: ubuntu-24.04 php-version: "7.4" runs-on: ${{ matrix.os }} @@ -197,7 +197,7 @@ jobs: - phpstan - unit-tests if: ${{ (github.event_name == 'workflow_call' || needs.check-ci-runs.outputs.ci_required == 1) && !cancelled() && !failure() }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: artifact_name: ${{ steps.run-build-script.outputs.artifact_name }} artifact_path: ${{ steps.run-build-script.outputs.artifact_path }} @@ -268,21 +268,21 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest + - ubuntu-24.04 - windows-latest - macos-latest php-version: - "8.4" include: - - os: ubuntu-latest + - os: ubuntu-24.04 php-version: "8.3" - - os: ubuntu-latest + - os: ubuntu-24.04 php-version: "8.2" - - os: ubuntu-latest + - os: ubuntu-24.04 php-version: "8.1" - - os: ubuntu-latest + - os: ubuntu-24.04 php-version: "8.0" - - os: ubuntu-latest + - os: ubuntu-24.04 php-version: "7.4" runs-on: ${{ matrix.os }} @@ -336,7 +336,7 @@ jobs: config: --include-if-php --preset wordpress . args: --quiet --timers --no-problems - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout ${{ matrix.repository }} diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 6d561ee6..c483bfec 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -15,7 +15,7 @@ concurrency: jobs: build: name: Build - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout @@ -66,7 +66,7 @@ jobs: name: github-pages url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Deploy to GitHub Pages diff --git a/.github/workflows/gc.yml b/.github/workflows/gc.yml index 68a31c0d..d0fed638 100644 --- a/.github/workflows/gc.yml +++ b/.github/workflows/gc.yml @@ -57,7 +57,7 @@ on: jobs: delete-runs: name: Delete workflow runs - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: actions: write diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b8ebd65f..94ec76b2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -35,7 +35,7 @@ jobs: homebrew: name: Update Homebrew formula if: ${{ github.event_name != 'workflow_dispatch' || inputs.update-homebrew }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Bump Homebrew formula and push to lkrms/misc tap @@ -52,7 +52,7 @@ jobs: aur: name: Update AUR package if: ${{ github.event_name != 'workflow_dispatch' || inputs.update-aur }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout @@ -80,7 +80,7 @@ jobs: vscode: name: Update VS Code extension if: ${{ github.event_name != 'workflow_dispatch' || inputs.update-vscode }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a031e5c0..0b2e35f4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,7 +8,7 @@ on: jobs: check-ci-runs: name: Check CI workflow runs - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: ci_required: ${{ steps.check-ci-runs.outputs.ci_required }} steps: @@ -32,7 +32,7 @@ jobs: needs: - ci if: ${{ !cancelled() && !failure() }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout From 1e4a855cb6f9fcdf013c3d85fd50f3abb7848482 Mon Sep 17 00:00:00 2001 From: Luke Arms Date: Wed, 8 Jan 2025 09:42:56 +1100 Subject: [PATCH 18/21] Update rule documentation --- docs/Rules.md | 35 ++++++++++++++-------------- src/Rule/AlignChains.php | 3 ++- src/Rule/AlignData.php | 11 +++++---- src/Rule/ControlStructureSpacing.php | 4 ++-- src/Rule/DeclarationSpacing.php | 2 +- src/Rule/FormatHeredocs.php | 4 ++-- src/Rule/IndexSpacing.php | 6 ++--- src/Rule/NormaliseComments.php | 4 ++-- src/Rule/PlaceBraces.php | 4 ++-- src/Rule/PlaceComments.php | 5 ++-- src/Rule/PreserveNewlines.php | 16 +++++++------ src/Rule/StandardSpacing.php | 2 +- src/Rule/StatementSpacing.php | 6 ++--- 13 files changed, 53 insertions(+), 49 deletions(-) diff --git a/docs/Rules.md b/docs/Rules.md index 2ceecfab..be3e14a8 100644 --- a/docs/Rules.md +++ b/docs/Rules.md @@ -61,7 +61,7 @@ Formatting rules applied by `pretty-php` are as follows. (mandatory, `processTokens()`, priority 40, tokens: `T_COMMENT` | `T_DOC_COMMENT`) -In one-line C-style comments (`/*`), unnecessary asterisks are removed from both delimiters, the remaining content is trimmed, and spaces are added between delimiters and adjacent content. +In one-line C-style comments (`/*`), unnecessary asterisks are removed from both delimiters, the remaining content is trimmed, and a space is added between delimiters and adjacent content. Shell-style comments (`#`) are converted to C++-style comments (`//`). @@ -77,7 +77,7 @@ DocBlocks are normalised for PSR-5 compliance as follows: Multi-line C-style comments where every line starts with an asterisk, or at least one delimiter appears on its own line, receive the same treatment as DocBlocks. -> Multi-line C-style comments that do not meet this criteria are trimmed and reindented by the renderer. +> Multi-line C-style comments that do not meet this criteria are trimmed and may be reindented by the renderer. ### `NormaliseStrings` @@ -109,15 +109,15 @@ In non-constant strings, whitespace between tokens is suppressed for inner sibli (mandatory, `processTokens()`, priority 62, tokens: `T_START_HEREDOC`) -If `HeredocIndent` has a value other than `NONE`, heredocs are saved for later processing. +If the formatter's `HeredocIndent` property has a value other than `NONE`, heredocs are saved for later processing. ### `IndexSpacing` (mandatory, `processTokens()`, priority 100) -Leading and trailing spaces are: +Leading and/or trailing spaces are: -- added to tokens in the `AddSpace`, `AddSpaceBefore` and `AddSpaceAfter` indexes +- added to tokens in the formatter's `AddSpace`, `AddSpaceBefore` and `AddSpaceAfter` indexes - suppressed, along with blank lines, for tokens in the `SuppressSpaceBefore` and `SuppressSpaceAfter` indexes, and inside brackets other than structural and `match` braces Blank lines are also suppressed inside alternative syntax blocks. @@ -152,7 +152,7 @@ Spaces are added before and after operators not mentioned above. (mandatory, `processTokens()`, priority 104, tokens: `,` | `T_DECLARE` | `T_MATCH` | `T_ATTRIBUTE` | `T_OPEN_TAG` | `T_OPEN_TAG_WITH_ECHO` | `T_CLOSE_TAG` | `T_START_HEREDOC` | `T_ATTRIBUTE_COMMENT`) -If the indentation level of an open tag aligns with a tab stop, and a close tag is found in the same scope (or the document has no close tag, and the open tag is in the global scope), a callback is registered to align nested tokens with it. An additional level of indentation is applied if `IndentBetweenTags` is enabled. +If the indentation level of an open tag aligns with a tab stop, and a close tag is found in the same scope (or the document has no close tag, and the open tag is in the global scope), a callback is registered to align nested tokens with it. An additional level of indentation is applied if the formatter's `IndentBetweenTags` property is `true`. If a ` Open brace placement is handled by `VerticalSpacing`, which runs after newlines are applied by other rules. @@ -221,7 +220,7 @@ Newlines are added before and after: These comments are also saved for alignment with the next code token (unless it's a close bracket). -Leading and trailing spaces are added to comments that don't appear on their own line, and comments where the previous token is a code token are saved to receive padding derived from `SpacesBesideCode` if they are the last token on the line after other rules are applied. +Leading and trailing spaces are added to comments that don't appear on their own line, and comments where the previous token is a code token are saved to receive padding derived from the value of the formatter's `SpacesBesideCode` property if they are the last token on the line after other rules are applied. For multi-line DocBlocks, and C-style comments that receive the same treatment: @@ -233,14 +232,14 @@ For multi-line DocBlocks, and C-style comments that receive the same treatment: (default, `processTokens()`, priority 200, tokens: `* (except virtual)`) -If a newline in the input is adjacent to a token in `AllowNewlineBefore` or `AllowNewlineAfter`, it is applied to the token as a leading or trailing newline on a best-effort basis. This has the effect of placing operators before or after newlines as per the formatter's token index. +If a newline in the input is adjacent to a token in the formatter's `AllowNewlineBefore` or `AllowNewlineAfter` indexes, it is applied to the token as a leading or trailing newline on a best-effort basis. This has the effect of placing operators before or after newlines as per the formatter's token index. -Similarly, blank lines in the input are preserved between tokens in `AllowBlankBefore` and `AllowBlankAfter`, except: +Similarly, blank lines in the input are preserved between tokens in the `AllowBlankBefore` and `AllowBlankAfter` indexes, except: - after `:` if there is a subsequent token in the same scope - after `,` other than between `match` expression arms - after `;` in `for` expressions -- after mid-statement comments and comments in non-statement scopes +- before and after mid-statement comments and comments in non-statement scopes ### `PreserveOneLineStatements` @@ -319,7 +318,7 @@ Newlines are added before and after control structure expressions with newlines (optional, `processTokens()`, priority 280, tokens: `T_OBJECT_OPERATOR` | `T_NULLSAFE_OBJECT_OPERATOR`) -If there are no object operators with a leading newline in a chain of method calls, or if the first object operator in the chain has a leading newline and `AlignChainAfterNewline` is disabled, no action is taken. +If there are no object operators with a leading newline in a chain of method calls, or if the first object operator in the chain has a leading newline and the formatter's `AlignChainAfterNewline` property is `false`, no action is taken. Otherwise, if the first object operator in the chain has a leading newline, it is removed if horizontal space on subsequent lines would be saved. Then, a callback is registered to align object operators in the chain with: @@ -335,7 +334,7 @@ One-line declarations with a collapsed or collapsible DocBlock, or no DocBlock a "Tight" spacing is applied by suppressing blank lines between collapsible declarations of the same type when they appear consecutively and: -- `TightDeclarationSpacing` is enabled, or +- the formatter's `TightDeclarationSpacing` property is `true`, or - there is no blank line in the input between the first and second declarations in the group DocBlocks in tightly-spaced groups are collapsed to a single line. @@ -512,9 +511,9 @@ This is achieved by: (optional, _`callback`_, priority 600) -Assignment operators are aligned unless `MaxAssignmentPadding` is not `null` and would be exceeded. +Assignment operators are aligned unless the formatter's `MaxAssignmentPadding` property is not `null` and would be exceeded. -In arrays and `match` expressions, `=>` delimiters are aligned unless `MaxDoubleArrowColumn` is not `null`, in which case any found in subsequent columns are excluded from consideration. +In arrays and `match` expressions, `=>` delimiters are aligned unless the formatter's `MaxDoubleArrowColumn` property is not `null`, in which case any found in subsequent columns are excluded from consideration. Alignment is achieved by: diff --git a/src/Rule/AlignChains.php b/src/Rule/AlignChains.php index 0706e6b6..270f1a1d 100644 --- a/src/Rule/AlignChains.php +++ b/src/Rule/AlignChains.php @@ -52,7 +52,8 @@ public static function needsSortedTokens(): bool * * If there are no object operators with a leading newline in a chain of * method calls, or if the first object operator in the chain has a leading - * newline and `AlignChainAfterNewline` is disabled, no action is taken. + * newline and the formatter's `AlignChainAfterNewline` property is `false`, + * no action is taken. * * Otherwise, if the first object operator in the chain has a leading * newline, it is removed if horizontal space on subsequent lines would be diff --git a/src/Rule/AlignData.php b/src/Rule/AlignData.php index 052b939c..493fa8c1 100644 --- a/src/Rule/AlignData.php +++ b/src/Rule/AlignData.php @@ -69,12 +69,13 @@ public function boot(): void * `AlignLists` nor `StrictLists` are enabled, its `=>` delimiters are * ignored. * - * @prettyphp-callback Assignment operators are aligned unless - * `MaxAssignmentPadding` is not `null` and would be exceeded. + * @prettyphp-callback Assignment operators are aligned unless the + * formatter's `MaxAssignmentPadding` property is not `null` and would be + * exceeded. * - * In arrays and `match` expressions, `=>` delimiters are aligned unless - * `MaxDoubleArrowColumn` is not `null`, in which case any found in - * subsequent columns are excluded from consideration. + * In arrays and `match` expressions, `=>` delimiters are aligned unless the + * formatter's `MaxDoubleArrowColumn` property is not `null`, in which case + * any found in subsequent columns are excluded from consideration. * * Alignment is achieved by: * diff --git a/src/Rule/ControlStructureSpacing.php b/src/Rule/ControlStructureSpacing.php index 841f7cbe..45b82e66 100644 --- a/src/Rule/ControlStructureSpacing.php +++ b/src/Rule/ControlStructureSpacing.php @@ -50,8 +50,8 @@ public static function needsSortedTokens(): bool * * If the body of a control structure has no enclosing braces: * - * - a newline is added after the body (if empty) - * - a newline is added before and after the body (if non-empty) + * - a newline is added after the body (if empty), or before and after the + * body (if non-empty) * - blank lines before the body are suppressed * - blank lines after the body are suppressed if the control structure * continues diff --git a/src/Rule/DeclarationSpacing.php b/src/Rule/DeclarationSpacing.php index c780e9a4..adae1878 100644 --- a/src/Rule/DeclarationSpacing.php +++ b/src/Rule/DeclarationSpacing.php @@ -77,7 +77,7 @@ public function boot(): void * "Tight" spacing is applied by suppressing blank lines between collapsible * declarations of the same type when they appear consecutively and: * - * - `TightDeclarationSpacing` is enabled, or + * - the formatter's `TightDeclarationSpacing` property is `true`, or * - there is no blank line in the input between the first and second * declarations in the group * diff --git a/src/Rule/FormatHeredocs.php b/src/Rule/FormatHeredocs.php index 6d586b5f..1da1802b 100644 --- a/src/Rule/FormatHeredocs.php +++ b/src/Rule/FormatHeredocs.php @@ -60,8 +60,8 @@ public function reset(): void /** * Apply the rule to the given tokens * - * If `HeredocIndent` has a value other than `NONE`, heredocs are saved for - * later processing. + * If the formatter's `HeredocIndent` property has a value other than + * `NONE`, heredocs are saved for later processing. */ public function processTokens(array $tokens): void { diff --git a/src/Rule/IndexSpacing.php b/src/Rule/IndexSpacing.php index f39a80cc..e1c17d3b 100644 --- a/src/Rule/IndexSpacing.php +++ b/src/Rule/IndexSpacing.php @@ -58,10 +58,10 @@ public static function needsSortedTokens(): bool /** * Apply the rule to the given tokens * - * Leading and trailing spaces are: + * Leading and/or trailing spaces are: * - * - added to tokens in the `AddSpace`, `AddSpaceBefore` and `AddSpaceAfter` - * indexes + * - added to tokens in the formatter's `AddSpace`, `AddSpaceBefore` and + * `AddSpaceAfter` indexes * - suppressed, along with blank lines, for tokens in the * `SuppressSpaceBefore` and `SuppressSpaceAfter` indexes, and inside * brackets other than structural and `match` braces diff --git a/src/Rule/NormaliseComments.php b/src/Rule/NormaliseComments.php index f91a4988..91fb6c75 100644 --- a/src/Rule/NormaliseComments.php +++ b/src/Rule/NormaliseComments.php @@ -51,7 +51,7 @@ public static function needsSortedTokens(): bool * Apply the rule to the given tokens * * In one-line C-style comments (`/*`), unnecessary asterisks are removed - * from both delimiters, the remaining content is trimmed, and spaces are + * from both delimiters, the remaining content is trimmed, and a space is * added between delimiters and adjacent content. * * Shell-style comments (`#`) are converted to C++-style comments (`//`). @@ -79,7 +79,7 @@ public static function needsSortedTokens(): bool * treatment as DocBlocks. * * > Multi-line C-style comments that do not meet this criteria are trimmed - * > and reindented by the renderer. + * > and may be reindented by the renderer. */ public function processTokens(array $tokens): void { diff --git a/src/Rule/PlaceBraces.php b/src/Rule/PlaceBraces.php index 729d1268..882b777e 100644 --- a/src/Rule/PlaceBraces.php +++ b/src/Rule/PlaceBraces.php @@ -70,8 +70,8 @@ public function reset(): void * expression or a control structure that is immediately continued, e.g. * `} else {`. In the latter case, trailing newlines are suppressed. * - Empty class, function and property hook bodies are collapsed to ` {}` - * on the same line as the declaration they belong to unless - * `CollapseEmptyDeclarationBodies` is disabled. + * on the same line as the declaration they belong to unless the + * formatter's `CollapseEmptyDeclarationBodies` property is `false`. * - Horizontal whitespace is suppressed between other empty braces. * * > Open brace placement is handled by `VerticalSpacing`, which runs after diff --git a/src/Rule/PlaceComments.php b/src/Rule/PlaceComments.php index 729d22cd..359c69fc 100644 --- a/src/Rule/PlaceComments.php +++ b/src/Rule/PlaceComments.php @@ -82,8 +82,9 @@ public function reset(): void * * Leading and trailing spaces are added to comments that don't appear on * their own line, and comments where the previous token is a code token are - * saved to receive padding derived from `SpacesBesideCode` if they are the - * last token on the line after other rules are applied. + * saved to receive padding derived from the value of the formatter's + * `SpacesBesideCode` property if they are the last token on the line after + * other rules are applied. * * For multi-line DocBlocks, and C-style comments that receive the same * treatment: diff --git a/src/Rule/PreserveNewlines.php b/src/Rule/PreserveNewlines.php index c191dce1..cf26784d 100644 --- a/src/Rule/PreserveNewlines.php +++ b/src/Rule/PreserveNewlines.php @@ -63,18 +63,20 @@ public function boot(): void /** * Apply the rule to the given tokens * - * If a newline in the input is adjacent to a token in `AllowNewlineBefore` - * or `AllowNewlineAfter`, it is applied to the token as a leading or - * trailing newline on a best-effort basis. This has the effect of placing - * operators before or after newlines as per the formatter's token index. + * If a newline in the input is adjacent to a token in the formatter's + * `AllowNewlineBefore` or `AllowNewlineAfter` indexes, it is applied to the + * token as a leading or trailing newline on a best-effort basis. This has + * the effect of placing operators before or after newlines as per the + * formatter's token index. * - * Similarly, blank lines in the input are preserved between tokens in - * `AllowBlankBefore` and `AllowBlankAfter`, except: + * Similarly, blank lines in the input are preserved between tokens in the + * `AllowBlankBefore` and `AllowBlankAfter` indexes, except: * * - after `:` if there is a subsequent token in the same scope * - after `,` other than between `match` expression arms * - after `;` in `for` expressions - * - after mid-statement comments and comments in non-statement scopes + * - before and after mid-statement comments and comments in non-statement + * scopes */ public function processTokens(array $tokens): void { diff --git a/src/Rule/StandardSpacing.php b/src/Rule/StandardSpacing.php index 6997b447..86b7c96b 100644 --- a/src/Rule/StandardSpacing.php +++ b/src/Rule/StandardSpacing.php @@ -90,7 +90,7 @@ public static function needsSortedDeclarations(): bool * close tag is found in the same scope (or the document has no close tag, * and the open tag is in the global scope), a callback is registered to * align nested tokens with it. An additional level of indentation is - * applied if `IndentBetweenTags` is enabled. + * applied if the formatter's `IndentBetweenTags` property is `true`. * * If a ` Date: Wed, 8 Jan 2025 12:21:21 +1100 Subject: [PATCH 19/21] Fix incorrect formatting in alternative syntax constructs - Fix issue where assignments in alternative syntax constructs are not aligned when `align-data` is enabled - Fix issue where alignment is incorrectly applied to default value assignments in parameter lists with no leading newline when `align-data` is enabled - Fix issue where alternative syntax constructs may not be indented correctly when `align-lists` is enabled - Fix issue where blank lines may not be added before `yield` statements in alternative syntax constructs when `blank-before-return` is enabled - Fix issue where blank lines before and after comments are incorrectly suppressed in alternative syntax constructs --- docs/Rules.md | 4 +- src/Rule/AlignData.php | 16 +- src/Rule/AlignLists.php | 22 +- src/Rule/BlankBeforeReturn.php | 5 +- src/Rule/HangingIndentation.php | 2 +- src/Rule/PreserveNewlines.php | 10 +- src/Rule/Preset/WordPress.php | 2 +- .../preset/wordpress/loop.out | 2 +- .../preset/wordpress/meta-boxes.out | 2 +- tests/unit/Rule/AlignDataTest.php | 236 +++++++++++++++++- tests/unit/Rule/AlignListsTest.php | 78 ++++++ 11 files changed, 355 insertions(+), 24 deletions(-) diff --git a/docs/Rules.md b/docs/Rules.md index be3e14a8..772f4158 100644 --- a/docs/Rules.md +++ b/docs/Rules.md @@ -456,11 +456,11 @@ C++- and shell-style comments on their own line after a comment beside code are When they appear in the same scope, a callback is registered to align consecutive: -- assignment operators +- assignment operators (except as noted below) - `=>` delimiters in array syntax (except as noted below) - `=>` delimiters in `match` expressions -If the open bracket of an array is not followed by a newline and neither `AlignLists` nor `StrictLists` are enabled, its `=>` delimiters are ignored. +If the open bracket of an array or parameter list is not followed by a newline and neither `AlignLists` nor `StrictLists` are enabled, its `=>` delimiters or assignment operators are ignored. ### `AlignChains` (2) diff --git a/src/Rule/AlignData.php b/src/Rule/AlignData.php index 493fa8c1..10c6d4df 100644 --- a/src/Rule/AlignData.php +++ b/src/Rule/AlignData.php @@ -61,13 +61,13 @@ public function boot(): void * When they appear in the same scope, a callback is registered to align * consecutive: * - * - assignment operators + * - assignment operators (except as noted below) * - `=>` delimiters in array syntax (except as noted below) * - `=>` delimiters in `match` expressions * - * If the open bracket of an array is not followed by a newline and neither - * `AlignLists` nor `StrictLists` are enabled, its `=>` delimiters are - * ignored. + * If the open bracket of an array or parameter list is not followed by a + * newline and neither `AlignLists` nor `StrictLists` are enabled, its `=>` + * delimiters or assignment operators are ignored. * * @prettyphp-callback Assignment operators are aligned unless the * formatter's `MaxAssignmentPadding` property is not `null` and would be @@ -112,7 +112,13 @@ public function processBlock(array $lines): void ( !$token->Parent || $token->Parent->Flags & TokenFlag::STRUCTURAL_BRACE - || $token->Parent->isParameterList() + || $token->Parent->id === \T_COLON + || ( + $token->Parent->isParameterList() && ( + $this->ListRuleEnabled + || $token->Parent->hasNewlineBeforeNextCode() + ) + ) ) // Ignore assignment operators after the first: // - in the statement diff --git a/src/Rule/AlignLists.php b/src/Rule/AlignLists.php index af2fc6d0..a7027910 100644 --- a/src/Rule/AlignLists.php +++ b/src/Rule/AlignLists.php @@ -117,16 +117,30 @@ static function () use ( if ($parent->CloseBracket) { // `]` after `2` -> `]` after `5` while (($adjacent = $to->lastSiblingBeforeNewline()) !== $to && !( - $adjacent->id === \T_OPEN_BRACE - && $adjacent->Flags & TokenFlag::STRUCTURAL_BRACE + ( + ( + $adjacent->id === \T_OPEN_BRACE + && $adjacent->Flags & TokenFlag::STRUCTURAL_BRACE + ) || ( + $adjacent->id === \T_COLON + && $adjacent->CloseBracket + ) + ) && $adjacent->Depth <= $parent->Depth )) { $to = $adjacent; } // `]` after `5` -> `+` -> `)` after `11` while (($adjacent = $to->adjacentBeforeNewline()) && !( - $adjacent->id === \T_OPEN_BRACE - && $adjacent->Flags & TokenFlag::STRUCTURAL_BRACE + ( + ( + $adjacent->id === \T_OPEN_BRACE + && $adjacent->Flags & TokenFlag::STRUCTURAL_BRACE + ) || ( + $adjacent->id === \T_COLON + && $adjacent->CloseBracket + ) + ) && $adjacent->Depth <= $parent->Depth )) { $to = TokenUtil::getOperatorEndExpression($adjacent); diff --git a/src/Rule/BlankBeforeReturn.php b/src/Rule/BlankBeforeReturn.php index 11468a6d..d9320118 100644 --- a/src/Rule/BlankBeforeReturn.php +++ b/src/Rule/BlankBeforeReturn.php @@ -55,7 +55,10 @@ public function processTokens(array $tokens): void if ( $token->Statement !== $token || ( $token->Parent - && !($token->Parent->Flags & TokenFlag::STRUCTURAL_BRACE) + && !( + $token->Parent->Flags & TokenFlag::STRUCTURAL_BRACE + || $token->Parent->id === \T_COLON + ) ) ) { continue; diff --git a/src/Rule/HangingIndentation.php b/src/Rule/HangingIndentation.php index b0b17672..9280bc6d 100644 --- a/src/Rule/HangingIndentation.php +++ b/src/Rule/HangingIndentation.php @@ -110,7 +110,7 @@ public function processTokens(array $tokens): void ) ) || ( $token->id === \T_COLON - && $token->isColonAltSyntaxDelimiter() + && $token->CloseBracket ) || $token->id === \T_OPEN_UNENCLOSED; $flags = 0; if ($token->hasNewlineBeforeNextCode()) { diff --git a/src/Rule/PreserveNewlines.php b/src/Rule/PreserveNewlines.php index cf26784d..c636ea12 100644 --- a/src/Rule/PreserveNewlines.php +++ b/src/Rule/PreserveNewlines.php @@ -246,8 +246,10 @@ private function maybePreserveNewlineAfter( && $prevCode->Parent === $parent && $prevCode->EndStatement !== $prevCode ) || ( - $parent - && !($parent->Flags & TokenFlag::STRUCTURAL_BRACE) + $parent && !( + $parent->Flags & TokenFlag::STRUCTURAL_BRACE + || $parent->id === \T_COLON + ) ) ) ) || ( @@ -258,8 +260,10 @@ private function maybePreserveNewlineAfter( && $prevCode->EndStatement !== $prevCode ) || ( $next->Parent - && !($next->Parent->Flags & TokenFlag::STRUCTURAL_BRACE) && !( + $next->Parent->Flags & TokenFlag::STRUCTURAL_BRACE + || $next->Parent->id === \T_COLON + ) && !( $next->Parent->id === \T_OPEN_BRACE && $next->Parent->isMatchOpenBrace() && ($prevCode = $next->PrevCode) diff --git a/src/Rule/Preset/WordPress.php b/src/Rule/Preset/WordPress.php index 39bb43ce..528ac490 100644 --- a/src/Rule/Preset/WordPress.php +++ b/src/Rule/Preset/WordPress.php @@ -136,7 +136,7 @@ public function processTokens(array $tokens): void } if ($token->id === \T_COLON) { - if (!$token->isColonAltSyntaxDelimiter()) { + if (!$token->CloseBracket) { continue; } $token->applyWhitespace(Space::SPACE_BEFORE); diff --git a/tests/fixtures/App/PrettyPHPCommand/preset/wordpress/loop.out b/tests/fixtures/App/PrettyPHPCommand/preset/wordpress/loop.out index 94cf4835..12c90c8b 100644 --- a/tests/fixtures/App/PrettyPHPCommand/preset/wordpress/loop.out +++ b/tests/fixtures/App/PrettyPHPCommand/preset/wordpress/loop.out @@ -78,7 +78,7 @@ while ( have_posts() ) : $images = twentyten_get_gallery_images(); if ( $images ) : $total_images = count( $images ); - $image = reset( $images ); + $image = reset( $images ); ?>