@@ -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 }
0 commit comments