@@ -139,276 +139,108 @@ module.exports = function serialize(obj, options) {
139139 }
140140
141141 function serializeFunc ( fn , options ) {
142- var serializedFn = fn . toString ( ) ;
143- if ( IS_NATIVE_CODE_REGEXP . test ( serializedFn ) ) {
144- throw new TypeError ( 'Serializing native function: ' + fn . name ) ;
145- }
146-
147- // If no space option, return original behavior
148- if ( ! options || ! options . space ) {
149- // pure functions, example: {key: function() {}}
150- if ( IS_PURE_FUNCTION . test ( serializedFn ) ) {
151- return serializedFn ;
142+ var serializedFn = fn . toString ( ) ;
143+ if ( IS_NATIVE_CODE_REGEXP . test ( serializedFn ) ) {
144+ throw new TypeError ( 'Serializing native function: ' + fn . name ) ;
152145 }
153146
154- // arrow functions, example: arg1 => arg1+5
155- if ( IS_ARROW_FUNCTION . test ( serializedFn ) ) {
156- return serializedFn ;
157- }
147+ // If no space option, use original behavior
148+ if ( ! options || ! options . space ) {
149+ // pure functions, example: {key: function() {}}
150+ if ( IS_PURE_FUNCTION . test ( serializedFn ) ) {
151+ return serializedFn ;
152+ }
158153
159- var argsStartsAt = serializedFn . indexOf ( '(' ) ;
160- var def = serializedFn . substr ( 0 , argsStartsAt )
161- . trim ( )
162- . split ( ' ' )
163- . filter ( function ( val ) { return val . length > 0 } ) ;
154+ // arrow functions, example: arg1 => arg1+5
155+ if ( IS_ARROW_FUNCTION . test ( serializedFn ) ) {
156+ return serializedFn ;
157+ }
164158
165- var nonReservedSymbols = def . filter ( function ( val ) {
166- return RESERVED_SYMBOLS . indexOf ( val ) === - 1
167- } ) ;
159+ var argsStartsAt = serializedFn . indexOf ( '(' ) ;
160+ var def = serializedFn . substr ( 0 , argsStartsAt )
161+ . trim ( )
162+ . split ( ' ' )
163+ . filter ( function ( val ) { return val . length > 0 } ) ;
164+
165+ var nonReservedSymbols = def . filter ( function ( val ) {
166+ return RESERVED_SYMBOLS . indexOf ( val ) === - 1
167+ } ) ;
168+
169+ // enhanced literal objects, example: {key() {}}
170+ if ( nonReservedSymbols . length > 0 ) {
171+ return ( def . indexOf ( 'async' ) > - 1 ? 'async ' : '' ) + 'function'
172+ + ( def . join ( '' ) . indexOf ( '*' ) > - 1 ? '*' : '' )
173+ + serializedFn . substr ( argsStartsAt ) ;
174+ }
168175
169- // enhanced literal objects, example: {key() {}}
170- if ( nonReservedSymbols . length > 0 ) {
171- return ( def . indexOf ( 'async' ) > - 1 ? 'async ' : '' ) + 'function'
172- + ( def . join ( '' ) . indexOf ( '*' ) > - 1 ? '*' : '' )
173- + serializedFn . substr ( argsStartsAt ) ;
176+ // arrow functions
177+ return serializedFn ;
174178 }
175179
176- // arrow functions
177- return serializedFn ;
178- }
179-
180- // Format function body with space option
181- return formatFunctionWithSpace ( serializedFn , options . space ) ;
180+ // Format function with space option - much simpler approach
181+ return formatFunctionWithSpace ( serializedFn , options . space ) ;
182182 }
183183
184184 function formatFunctionWithSpace ( serializedFn , space ) {
185- // Determine indentation unit
186- var indentUnit ;
187- if ( typeof space === 'number' ) {
188- indentUnit = ' ' . repeat ( space ) ;
189- } else if ( typeof space === 'string' ) {
190- indentUnit = space ;
191- } else {
192- return serializedFn ; // fallback to original
193- }
194-
195- // Find the function body opening brace (not parameter destructuring braces)
196- var bodyStartBraceIndex = - 1 ;
197- var parenDepth = 0 ;
198- var braceDepth = 0 ;
199-
200- for ( var i = 0 ; i < serializedFn . length ; i ++ ) {
201- var char = serializedFn [ i ] ;
202- if ( char === '(' ) {
203- parenDepth ++ ;
204- } else if ( char === ')' ) {
205- parenDepth -- ;
206- // After closing the parameter list, the next { is the function body
207- if ( parenDepth === 0 ) {
208- for ( var j = i + 1 ; j < serializedFn . length ; j ++ ) {
209- if ( serializedFn [ j ] === '{' ) {
210- bodyStartBraceIndex = j ;
211- break ;
212- } else if ( serializedFn [ j ] !== ' ' && serializedFn [ j ] !== '=' && serializedFn [ j ] !== '>' ) {
213- // Non-space/arrow character before brace, not a function body brace
214- break ;
215- }
216- }
217- break ;
218- }
219- }
220- }
221-
222- var closeBraceIndex = serializedFn . lastIndexOf ( '}' ) ;
223-
224- if ( bodyStartBraceIndex === - 1 || closeBraceIndex === - 1 || bodyStartBraceIndex >= closeBraceIndex ) {
225- return serializedFn ; // No function body braces found, return original
226- }
227-
228- var signature = serializedFn . substring ( 0 , bodyStartBraceIndex ) . trim ( ) ;
229- var body = serializedFn . substring ( bodyStartBraceIndex + 1 , closeBraceIndex ) . trim ( ) ;
230-
231- // Clean up signature: ensure proper spacing
232- // For arrow functions, add space around =>
233- if ( signature . includes ( '=>' ) ) {
234- signature = signature . replace ( / \s * = > \s * / , ' => ' ) ;
235- }
236-
237- // Ensure space before opening brace
238- if ( ! signature . endsWith ( ' ' ) ) {
239- signature += ' ' ;
240- }
241-
242- // If body is empty, format minimally
243- if ( ! body ) {
244- return signature + '{\n' + indentUnit . repeat ( 2 ) + '}' ;
245- }
246-
247- // Format the function body with proper indentation and spacing
248- var formattedBody = formatSimpleFunctionBody ( body , indentUnit ) ;
249-
250- // Ensure we don't double-add closing braces
251- var lines = formattedBody . split ( '\n' ) ;
252- var lastNonEmptyIndex = lines . length - 1 ;
253- while ( lastNonEmptyIndex >= 0 && ! lines [ lastNonEmptyIndex ] . trim ( ) ) {
254- lastNonEmptyIndex -- ;
255- }
256-
257- if ( lastNonEmptyIndex >= 0 && lines [ lastNonEmptyIndex ] . trim ( ) === '}' ) {
258- // Remove the last closing brace line
259- lines . splice ( lastNonEmptyIndex , 1 ) ;
260- formattedBody = lines . join ( '\n' ) ;
261- }
262-
263- return signature + '{\n' + formattedBody + '\n' + indentUnit + '}' ;
264- }
265-
266- function formatSimpleFunctionBody ( body , indentUnit ) {
267- // Enhanced function body formatter that handles nested structures
268- var baseIndent = indentUnit . repeat ( 2 ) ; // Functions are already inside objects, so depth 2
269-
270- // First, add spaces around operators and keywords, being careful about arrow functions
271- var formatted = body
272- // Protect arrow functions from being split
273- . replace ( / = > / g, '___ARROW___' )
274- // Clean up multiple spaces first
275- . replace ( / \s + / g, ' ' )
276- // Add spaces around operators (but not === or !==)
277- . replace ( / ( [ ^ = ! < > ] ) \s * = \s * ( [ ^ = ] ) / g, '$1 = $2' )
278- . replace ( / ( [ ^ = ] ) \s * = = = \s * ( [ ^ = ] ) / g, '$1 === $2' )
279- . replace ( / ( [ ^ ! ] ) \s * ! = = \s * ( [ ^ = ] ) / g, '$1 !== $2' )
280- . replace ( / ( [ ^ | ] ) \s * \| \| \s * ( [ ^ | ] ) / g, '$1 || $2' )
281- . replace ( / ( [ ^ & ] ) \s * & & \s * ( [ ^ & ] ) / g, '$1 && $2' )
282- // Add spaces around arithmetic operators
283- . replace ( / ( [ ^ \s * ] ) \s * \* \s * ( [ ^ \s * ] ) / g, '$1 * $2' )
284- . replace ( / ( [ ^ \s + ] ) \s * \+ \s * ( [ ^ \s + ] ) / g, '$1 + $2' )
285- . replace ( / ( [ ^ \s - ] ) \s * - \s * ( [ ^ \s - ] ) / g, '$1 - $2' )
286- . replace ( / ( [ ^ \s / ] ) \s * \/ \s * ( [ ^ \s / ] ) / g, '$1 / $2' )
287- // Add spaces around comparison operators
288- . replace ( / ( [ ^ \s > ] ) \s * > \s * ( [ ^ \s > = ] ) / g, '$1 > $2' )
289- . replace ( / ( [ ^ \s < ] ) \s * < \s * ( [ ^ \s < = ] ) / g, '$1 < $2' )
290- . replace ( / \s * > = \s * (? ! [ > ] ) / g, ' >= ' )
291- . replace ( / \s * < = \s * (? ! [ < ] ) / g, ' <= ' )
292- // Add spaces after commas
293- . replace ( / , (? ! \s ) / g, ', ' )
294- // Add space after control keywords and before braces
295- . replace ( / \b ( i f | f o r | w h i l e ) \s * \( / g, '$1 (' )
296- . replace ( / \) \s * \{ / g, ') {' )
297- . replace ( / \b e l s e \s * \{ / g, 'else {' )
298- . replace ( / \b r e t u r n \s + ( [ ^ \s ] ) / g, 'return $1' )
299- // Restore arrow functions
300- . replace ( / _ _ _ A R R O W _ _ _ / g, ' => ' ) ;
301-
302- // Parse and format the statements with proper line breaks and nesting
303- return formatCodeWithNesting ( formatted , baseIndent , indentUnit ) ;
304- }
305-
306- function formatCodeWithNesting ( code , baseIndent , indentUnit ) {
307- var result = '' ;
308- var lines = [ ] ;
309- var current = '' ;
310- var braceDepth = 0 ;
311- var inString = false ;
312- var stringChar = '' ;
313-
314- // First pass: break into logical lines, handling } else { pattern
315- for ( var i = 0 ; i < code . length ; i ++ ) {
316- var char = code [ i ] ;
185+ // Determine indent string
186+ var indent = typeof space === 'number' ? ' ' . repeat ( space ) : ( space || ' ' ) ;
187+ var functionIndent = indent . repeat ( 2 ) ; // Functions are at depth 2 (inside object)
317188
318- // Handle strings
319- if ( ! inString && ( char === '"' || char === "'" || char === '`' ) ) {
320- inString = true ;
321- stringChar = char ;
322- } else if ( inString && char === stringChar && code [ i - 1 ] !== '\\' ) {
323- inString = false ;
324- stringChar = '' ;
325- }
189+ // Find function body bounds - need to find the { that's after the parameter list
190+ var parenDepth = 0 ;
191+ var bodyStart = - 1 ;
326192
327- if ( ! inString ) {
328- if ( char === '{' ) {
329- current += char ;
330- lines . push ( current . trim ( ) ) ;
331- current = '' ;
332- braceDepth ++ ;
333- continue ;
334- } else if ( char === '}' ) {
335- if ( current . trim ( ) ) {
336- lines . push ( current . trim ( ) ) ;
337- }
338- braceDepth -- ;
339-
340- // Check for } else { pattern
341- var nextNonWhitespace = '' ;
342- var j = i + 1 ;
343- while ( j < code . length && / \s / . test ( code [ j ] ) ) {
344- j ++ ;
345- }
346- if ( j < code . length - 4 && code . substring ( j , j + 4 ) === 'else' ) {
347- // Skip to after 'else'
348- j += 4 ;
349- while ( j < code . length && / \s / . test ( code [ j ] ) ) {
350- j ++ ;
351- }
352- if ( j < code . length && code [ j ] === '{' ) {
353- // This is } else {
354- lines . push ( '} else {' ) ;
355- i = j ; // Skip to the {
356- braceDepth ++ ;
357- current = '' ;
358- continue ;
359- }
193+ for ( var i = 0 ; i < serializedFn . length ; i ++ ) {
194+ var char = serializedFn [ i ] ;
195+ if ( char === '(' ) {
196+ parenDepth ++ ;
197+ } else if ( char === ')' ) {
198+ parenDepth -- ;
199+ } else if ( char === '{' && parenDepth === 0 ) {
200+ // This is a brace outside of parentheses, likely the function body
201+ bodyStart = i ;
202+ break ;
360203 }
361-
362- lines . push ( '}' ) ;
363- current = '' ;
364- continue ;
365- } else if ( char === ';' ) {
366- current += char ;
367- lines . push ( current . trim ( ) ) ;
368- current = '' ;
369- continue ;
370- }
371204 }
372205
373- current += char ;
374- }
375-
376- // Add any remaining content
377- if ( current . trim ( ) ) {
378- lines . push ( current . trim ( ) ) ;
379- }
380-
381- // Second pass: apply proper indentation
382- var currentDepth = 2 ; // Start at depth 2 for function bodies (object has 1, function has 2)
383- for ( var k = 0 ; k < lines . length ; k ++ ) {
384- var line = lines [ k ] . trim ( ) ;
385- if ( ! line ) continue ;
206+ var bodyEnd = serializedFn . lastIndexOf ( '}' ) ;
386207
387- // Adjust depth for closing braces
388- if ( line === '}' || line . startsWith ( '}' ) ) {
389- currentDepth -- ;
208+ if ( bodyStart === - 1 || bodyEnd === - 1 || bodyStart >= bodyEnd ) {
209+ return serializedFn ; // No function body found
390210 }
391211
392- // Apply indentation
393- result += indentUnit . repeat ( currentDepth ) + line ;
212+ var signature = serializedFn . substring ( 0 , bodyStart ) . trim ( ) ;
213+ var body = serializedFn . substring ( bodyStart + 1 , bodyEnd ) . trim ( ) ;
394214
395- // Add newline except for last line
396- if ( k < lines . length - 1 ) {
397- result += '\n' ;
215+ // Clean up signature spacing for arrow functions
216+ if ( signature . includes ( '=>' ) ) {
217+ signature = signature . replace ( / \s * = > \s * / , ' => ' ) ;
398218 }
399219
400- // Adjust depth for opening braces
401- if ( line . endsWith ( '{' ) ) {
402- currentDepth ++ ;
220+ // Handle empty body
221+ if ( ! body ) {
222+ return signature + ' {\n' + functionIndent + '\n' + indent + '}' ;
403223 }
404224
405- // Add semicolon if missing (except for braces)
406- if ( ! line . endsWith ( ';' ) && ! line . endsWith ( '{' ) && line !== '}' && ! line . startsWith ( '}' ) ) {
407- result = result . replace ( / ( [ ^ ; } ] ) $ / , '$1;' ) ;
408- }
409- }
410-
411- return result ;
225+ // Minimal formatting: split by semicolons and add basic spacing
226+ var statements = body . split ( ';' ) . filter ( function ( s ) { return s . trim ( ) ; } ) ;
227+ var formattedStatements = statements . map ( function ( stmt ) {
228+ var trimmed = stmt . trim ( ) ;
229+
230+ // Basic operator spacing (minimal set to avoid complexity)
231+ trimmed = trimmed
232+ . replace ( / = = = (? ! = ) / g, ' === ' )
233+ . replace ( / ! = = (? ! = ) / g, ' !== ' )
234+ . replace ( / ( [ ^ = ] ) = ( [ ^ = ] ) / g, '$1 = $2' )
235+ . replace ( / \| \| / g, ' || ' )
236+ . replace ( / & & / g, ' && ' )
237+ . replace ( / , (? ! \s ) / g, ', ' )
238+ . replace ( / \s + / g, ' ' ) ;
239+
240+ return functionIndent + trimmed + ( trimmed ? ';' : '' ) ;
241+ } ) ;
242+
243+ return signature + ' {\n' + formattedStatements . join ( '\n' ) + '\n' + indent + '}' ;
412244 } // Check if the parameter is function
413245 if ( options . ignoreFunction && typeof obj === "function" ) {
414246 obj = undefined ;
0 commit comments