@@ -251,32 +251,113 @@ function parseRedirectsJs(filePath: string): {
251251 return { developerDocsRedirects, userDocsRedirects} ;
252252}
253253
254+ /**
255+ * Extracts a string value from a JavaScript string literal, handling escaped quotes
256+ * Supports both single and double quotes
257+ */
258+ function extractStringValue (
259+ content : string ,
260+ startIndex : number
261+ ) : { endIndex : number ; value : string } | null {
262+ const quoteChar = content [ startIndex ] ;
263+ if ( quoteChar !== '"' && quoteChar !== "'" ) {
264+ return null ;
265+ }
266+
267+ let value = '' ;
268+ let i = startIndex + 1 ; // Start after the opening quote
269+
270+ while ( i < content . length ) {
271+ const char = content [ i ] ;
272+
273+ if ( char === '\\' ) {
274+ // Handle escaped characters
275+ if ( i + 1 < content . length ) {
276+ const nextChar = content [ i + 1 ] ;
277+
278+ // Special case: \\" should be parsed as \" (escaped quote)
279+ // In JavaScript: \\ escapes the backslash, \" escapes the quote
280+ // So \\" becomes \" (backslash + quote) in the string value
281+ if ( nextChar === '\\' && i + 2 < content . length && content [ i + 2 ] === quoteChar ) {
282+ // This is \\" which should be parsed as \" (escaped quote)
283+ value += '\\' + quoteChar ;
284+ i += 3 ;
285+ continue ;
286+ }
287+
288+ // Handle escaped quote, backslash, and other escape sequences
289+ if ( nextChar === quoteChar || nextChar === '\\' ) {
290+ value += char + nextChar ;
291+ i += 2 ;
292+ continue ;
293+ }
294+ // Handle other escape sequences like \n, \t, etc.
295+ value += char + nextChar ;
296+ i += 2 ;
297+ continue ;
298+ }
299+ // Backslash at end of string - treat as literal
300+ value += char ;
301+ i ++ ;
302+ } else if ( char === quoteChar ) {
303+ // Found closing quote (not escaped)
304+ return { endIndex : i , value} ;
305+ } else {
306+ value += char ;
307+ i ++ ;
308+ }
309+ }
310+
311+ // No closing quote found
312+ return null ;
313+ }
314+
254315/**
255316 * Extracts redirect objects from JavaScript array string
256- * Handles both single and double quotes, and whitespace variations
317+ * Handles both single and double quotes, escaped quotes, and flexible property order
257318 */
258319function extractRedirectsFromArray ( arrayContent : string ) : Redirect [ ] {
259320 const redirects : Redirect [ ] = [ ] ;
260321
261- // Match redirect objects with more flexible whitespace handling
262- // Handles both ' and " quotes, and various whitespace patterns including multiline
263- // The pattern needs to match objects that span multiple lines
264- const redirectRegex =
265- / \{ [ \s \S ] * ?s o u r c e : \s * [ ' " ] ( [ ^ ' " ] + ) [ ' " ] [ \s \S ] * ?d e s t i n a t i o n : \s * [ ' " ] ( [ ^ ' " ] + ) [ ' " ] [ \s \S ] * ?\} / g;
322+ // Match redirect objects - handle both source-first and destination-first orders
323+ // Look for opening brace, then find source and destination properties in any order
324+ const objectRegex = / \{ [ \s \S ] * ?\} / g;
325+
326+ let objectMatch : RegExpExecArray | null = objectRegex . exec ( arrayContent ) ;
327+ while ( objectMatch !== null ) {
328+ const objectContent = objectMatch [ 0 ] ;
329+ let source : string | null = null ;
330+ let destination : string | null = null ;
331+
332+ // Find source property
333+ const sourceMatch = objectContent . match ( / s o u r c e \s * : \s * ( [ ' " ] ) / ) ;
334+ if ( sourceMatch && sourceMatch . index !== undefined ) {
335+ const stringStart = sourceMatch . index + sourceMatch [ 0 ] . length - 1 ; // Position of quote char
336+ const result = extractStringValue ( objectContent , stringStart ) ;
337+ if ( result ) {
338+ source = result . value ;
339+ }
340+ }
266341
267- let match : RegExpExecArray | null = redirectRegex . exec ( arrayContent ) ;
268- while ( match !== null ) {
269- const source = match [ 1 ] ;
270- const destination = match [ 2 ] ;
342+ // Find destination property
343+ const destMatch = objectContent . match ( / d e s t i n a t i o n \s * : \s * ( [ ' " ] ) / ) ;
344+ if ( destMatch && destMatch . index !== undefined ) {
345+ const stringStart = destMatch . index + destMatch [ 0 ] . length - 1 ; // Position of quote char
346+ const result = extractStringValue ( objectContent , stringStart ) ;
347+ if ( result ) {
348+ destination = result . value ;
349+ }
350+ }
271351
352+ // If both properties found, add to redirects
272353 if ( source && destination ) {
273354 redirects . push ( {
274355 source,
275356 destination,
276357 } ) ;
277358 }
278359
279- match = redirectRegex . exec ( arrayContent ) ;
360+ objectMatch = objectRegex . exec ( arrayContent ) ;
280361 }
281362
282363 return redirects ;
0 commit comments