Skip to content

Commit 6f66992

Browse files
committed
Fix up array formatting.
1 parent 2d6ca9d commit 6f66992

File tree

4 files changed

+113
-22
lines changed

4 files changed

+113
-22
lines changed

PhpCollective/Sniffs/Formatting/ArrayDeclarationSniff.php

Lines changed: 91 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,26 @@ class ArrayDeclarationSniff implements Sniff
3636
*/
3737
public string $multiLineIndentationMode = 'assoc';
3838

39+
/**
40+
* Maximum number of non-associative items allowed on a single line.
41+
* When exceeded, items will be split to multiple lines.
42+
* Set to 0 to disable this check.
43+
*
44+
* @var int
45+
*/
46+
public int $maxNonAssocItemsPerLine = 10;
47+
48+
/**
49+
* Action to take when non-associative items exceed the limit.
50+
*
51+
* Options:
52+
* - 'chunk' (default): Group items into chunks of maxNonAssocItemsPerLine
53+
* - 'split': Put each item on its own line
54+
*
55+
* @var string
56+
*/
57+
public string $nonAssocExceedAction = 'chunk';
58+
3959
/**
4060
* @inheritDoc
4161
*/
@@ -555,26 +575,49 @@ protected function processMultiLineIndentation(File $phpcsFile, int $arrayStart,
555575

556576
// Check if we should process these items based on configuration
557577
$shouldProcess = false;
558-
if ($this->multiLineIndentationMode === 'all') {
559-
$shouldProcess = true;
560-
} else {
561-
// In 'assoc' mode, only process if at least one item on this line is associative
562-
foreach ($items as $item) {
563-
if ($item['is_associative']) {
564-
$shouldProcess = true;
578+
$hasAssociative = false;
579+
$nonAssocCount = 0;
565580

566-
break;
567-
}
581+
// Count associative and non-associative items
582+
foreach ($items as $item) {
583+
if ($item['is_associative']) {
584+
$hasAssociative = true;
585+
} else {
586+
$nonAssocCount++;
568587
}
569588
}
570589

590+
if ($this->multiLineIndentationMode === 'all') {
591+
$shouldProcess = true;
592+
} elseif ($this->multiLineIndentationMode === 'assoc' && $hasAssociative) {
593+
// In 'assoc' mode with associative items
594+
$shouldProcess = true;
595+
} elseif ($this->maxNonAssocItemsPerLine > 0 && $nonAssocCount > $this->maxNonAssocItemsPerLine) {
596+
// Check if non-associative items exceed the limit
597+
$shouldProcess = true;
598+
}
599+
571600
if (!$shouldProcess) {
572601
continue;
573602
}
574603

575604
foreach ($items as $i => $pair) {
576-
// In 'assoc' mode, only flag associative items
577-
if ($this->multiLineIndentationMode === 'assoc' && !$pair['is_associative']) {
605+
// Determine if this item should be flagged
606+
$shouldFlag = false;
607+
608+
if ($this->multiLineIndentationMode === 'all') {
609+
$shouldFlag = true;
610+
} elseif ($this->multiLineIndentationMode === 'assoc' && $hasAssociative) {
611+
// In 'assoc' mode with mixed items, only skip non-associative if no limit exceeded
612+
if ($pair['is_associative'] || ($this->maxNonAssocItemsPerLine > 0 && $nonAssocCount > $this->maxNonAssocItemsPerLine)) {
613+
$shouldFlag = true;
614+
}
615+
} elseif ($this->maxNonAssocItemsPerLine > 0 && $nonAssocCount > $this->maxNonAssocItemsPerLine) {
616+
// Non-associative array exceeds limit
617+
$shouldFlag = true;
618+
}
619+
620+
if (!$shouldFlag) {
578621
continue;
579622
}
580623

@@ -652,26 +695,53 @@ protected function processMultiLineIndentation(File $phpcsFile, int $arrayStart,
652695
}
653696

654697
$phpcsFile->fixer->beginChangeset();
698+
699+
// Determine if we should use chunking for this line
700+
$useChunking = false;
701+
if (
702+
$this->nonAssocExceedAction === 'chunk' &&
703+
$this->maxNonAssocItemsPerLine > 0 &&
704+
$nonAssocCount > $this->maxNonAssocItemsPerLine &&
705+
!$hasAssociative
706+
) {
707+
// Use chunking only for pure non-associative arrays
708+
$useChunking = true;
709+
}
710+
711+
$nonAssocIndex = 0;
655712
foreach ($items as $j => $p) {
656713
if ($j === 0) {
657714
continue;
658715
}
659716

660-
// In 'assoc' mode, when we have mixed items on a line, we need to fix all of them
661-
// Don't skip non-associative items when they're on the same line as associative ones
662-
663717
$targetPtr = $p['key'] ?? $p['value'];
664718

665-
// Find any whitespace before the target token and remove it
666-
$prevToken = $targetPtr - 1;
667-
while ($prevToken >= $arrayStart && in_array($tokens[$prevToken]['code'], [T_WHITESPACE, T_COMMA], true)) {
668-
if ($tokens[$prevToken]['code'] === T_WHITESPACE) {
669-
$phpcsFile->fixer->replaceToken($prevToken, '');
719+
// Determine if we should add a newline before this item
720+
$shouldAddNewline = false;
721+
722+
if ($useChunking && !$p['is_associative']) {
723+
// For chunking non-associative items
724+
$nonAssocIndex++;
725+
if ($nonAssocIndex % $this->maxNonAssocItemsPerLine === 0) {
726+
$shouldAddNewline = true;
670727
}
671-
$prevToken--;
728+
} else {
729+
// Default behavior: newline before each item (except first)
730+
$shouldAddNewline = true;
672731
}
673732

674-
$phpcsFile->fixer->addContentBefore($targetPtr, "\n" . $baseIndent);
733+
if ($shouldAddNewline) {
734+
// Find any whitespace before the target token and remove it
735+
$prevToken = $targetPtr - 1;
736+
while ($prevToken >= $arrayStart && in_array($tokens[$prevToken]['code'], [T_WHITESPACE, T_COMMA], true)) {
737+
if ($tokens[$prevToken]['code'] === T_WHITESPACE) {
738+
$phpcsFile->fixer->replaceToken($prevToken, '');
739+
}
740+
$prevToken--;
741+
}
742+
743+
$phpcsFile->fixer->addContentBefore($targetPtr, "\n" . $baseIndent);
744+
}
675745
}
676746
$phpcsFile->fixer->endChangeset();
677747
}

tests/PhpCollective/Sniffs/Formatting/ArrayDeclarationSniffTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class ArrayDeclarationSniffTest extends TestCase
1717
*/
1818
public function testDocBlockConstSniffer(): void
1919
{
20-
$this->assertSnifferFindsErrors(new ArrayDeclarationSniff(), 4);
20+
$this->assertSnifferFindsErrors(new ArrayDeclarationSniff(), 5);
2121
}
2222

2323
/**

tests/_data/ArrayDeclaration/after.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,16 @@ public function test(): void
3636
$uuid,
3737
'?' => ['pdf' => 1],
3838
];
39+
40+
// Non-associative array exceeding default limit of 10 items - SHOULD be flagged
41+
$longArray = [
42+
'item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7', 'item8', 'item9', 'item10',
43+
'item11',
44+
];
45+
46+
// Non-associative array at limit of 10 items - should NOT be flagged
47+
$limitArray = [
48+
'item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7', 'item8', 'item9', 'item10',
49+
];
3950
}
4051
}

tests/_data/ArrayDeclaration/before.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,15 @@ public function test(): void
3131
'action' => 'view', $uuid,
3232
'?' => ['pdf' => 1],
3333
];
34+
35+
// Non-associative array exceeding default limit of 10 items - SHOULD be flagged
36+
$longArray = [
37+
'item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7', 'item8', 'item9', 'item10', 'item11',
38+
];
39+
40+
// Non-associative array at limit of 10 items - should NOT be flagged
41+
$limitArray = [
42+
'item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7', 'item8', 'item9', 'item10',
43+
];
3444
}
3545
}

0 commit comments

Comments
 (0)