@@ -70,19 +70,11 @@ public function handle(): void
7070 preg_match_all ('/(basset|@bassetArchive|@bassetDirectory)\((.+)\)/ ' , $ content , $ matches );
7171
7272 $ matches [2 ] = collect ($ matches [2 ])
73- ->map (fn ($ match ) => collect (explode (', ' , $ match ))
74- ->map (function ($ arg ) {
75- try {
76- return eval ("return $ arg; " );
77- } catch (Throwable $ th ) {
78- return false ;
79- }
80- })
81- ->toArray ()
82- );
73+ ->map (fn ($ match ) => $ this ->parseBassetArguments ($ match ));
8374
8475 return collect ($ matches [1 ])->map (fn (string $ type , int $ i ) => [$ type , $ matches [2 ][$ i ]]);
8576 });
77+
8678 $ totalBassets = count ($ bassets );
8779 if (! $ totalBassets ) {
8880 $ this ->line ('No bassets found. ' );
@@ -165,6 +157,91 @@ public function handle(): void
165157 $ this ->info (sprintf ('Done in %.2fs ' , microtime (true ) - $ starttime ));
166158 }
167159
160+ /**
161+ * Parse basset arguments from a string, respecting array boundaries and quotes.
162+ *
163+ * @param string $argumentString
164+ * @return array
165+ */
166+ private function parseBassetArguments (string $ argumentString ): array
167+ {
168+ $ length = strlen ($ argumentString );
169+ $ arguments = [];
170+ $ current = '' ;
171+ $ state = [
172+ 'inQuotes ' => false ,
173+ 'quoteChar ' => null ,
174+ 'bracketDepth ' => 0 ,
175+ 'parenDepth ' => 0 ,
176+ ];
177+
178+ for ($ i = 0 ; $ i < $ length ; $ i ++) {
179+ $ char = $ argumentString [$ i ];
180+ $ isEscaped = $ i > 0 && $ argumentString [$ i - 1 ] === '\\' ;
181+
182+ if (in_array ($ char , ['" ' , "' " ], true ) && ! $ isEscaped ) {
183+ if (! $ state ['inQuotes ' ]) {
184+ $ state ['inQuotes ' ] = true ;
185+ $ state ['quoteChar ' ] = $ char ;
186+ } elseif ($ char === $ state ['quoteChar ' ]) {
187+ $ state ['inQuotes ' ] = false ;
188+ $ state ['quoteChar ' ] = null ;
189+ }
190+ $ current .= $ char ;
191+ continue ;
192+ }
193+
194+ if ($ state ['inQuotes ' ]) {
195+ $ current .= $ char ;
196+ continue ;
197+ }
198+
199+ $ state ['bracketDepth ' ] += match ($ char ) {
200+ '[ ' => 1 ,
201+ '] ' => -1 ,
202+ default => 0 ,
203+ };
204+
205+ $ state ['parenDepth ' ] += match ($ char ) {
206+ '( ' => 1 ,
207+ ') ' => -1 ,
208+ default => 0 ,
209+ };
210+
211+ if ($ char === ', ' && $ state ['bracketDepth ' ] === 0 && $ state ['parenDepth ' ] === 0 ) {
212+ $ arguments [] = $ this ->evaluateArgument (trim ($ current ));
213+ $ current = '' ;
214+ } else {
215+ $ current .= $ char ;
216+ }
217+ }
218+
219+ if (($ finalArg = trim ($ current )) !== '' ) {
220+ $ arguments [] = $ this ->evaluateArgument ($ finalArg );
221+ }
222+
223+ return $ arguments ;
224+ }
225+
226+ /**
227+ * Safely evaluate a single argument string.
228+ *
229+ * @param string $argument
230+ * @return mixed
231+ */
232+ private function evaluateArgument (string $ argument ): mixed
233+ {
234+ if ($ argument === '' ) {
235+ return false ;
236+ }
237+
238+ try {
239+ return eval ("return $ argument; " );
240+ } catch (Throwable ) {
241+ return false ;
242+ }
243+ }
244+
168245 /**
169246 * Gets all blade files in a directory recursively.
170247 *
0 commit comments