@@ -472,7 +472,7 @@ export class LocalStorageFS extends AbstractFileSystem {
472472
473473 if ( ! migrations . array_to_b64 ) {
474474 // eslint-disable-next-line @typescript-eslint/no-use-before-define
475- migrate_old_array_fs ( JSON . parse ( localStorage . getItem ( "fs" ) ) , true ) ;
475+ migrate_old_array_fs ( JSON . parse ( localStorage . getItem ( "fs" ) ) ) ;
476476 }
477477
478478 // mark all migrations as done
@@ -491,6 +491,7 @@ const migrate_old_string_fs = (state: object, is_outer = false) => {
491491 // migration step: we used to use a string but now we use an array for files
492492 // need to iterate DEEPLY into nested objects and convert string values to arrays
493493 // (so recurse)
494+ // TODO make iterative
494495
495496 for ( const key of Object . keys ( state ) ) {
496497 if ( typeof state [ key ] === "object" && ! Array . isArray ( state [ key ] ) ) {
@@ -507,26 +508,45 @@ const migrate_old_string_fs = (state: object, is_outer = false) => {
507508 }
508509}
509510
510- const migrate_old_array_fs = ( state : object , is_outer = false ) => {
511- // migration step: we used to use an array for files but now we use base64 strings (not the same as old comma string format)
511+ const migrate_old_array_fs = ( state : object ) => {
512+ // migration step: we used to use an array for files but now we use base64 strings
512513 // need to iterate DEEPLY into nested objects and convert array values to strings
513- // (so recurse)
514514
515- for ( const key of Object . keys ( state ) ) {
516- if ( typeof state [ key ] === "object" && ! Array . isArray ( state [ key ] ) ) {
517- migrate_old_array_fs ( state [ key ] ) ;
518- } else if ( Array . isArray ( state [ key ] ) ) {
519- console . log ( `Migration: converting ${ key } to byte string` ) ;
515+ // use a stack to avoid recursion limit issues
516+ const stack = [ state ] ;
517+
518+ while ( stack . length > 0 ) {
519+ // get the next object to process
520+ const current_obj = stack . pop ( ) ;
520521
521- const values = state [ key ] . map ( ( x : string ) => parseInt ( x ) ) ;
522- const uint = new Uint8Array ( values ) ;
523- // uint.toBase64() isnt mainstream yet
524- state [ key ] = btoa ( String . fromCharCode . apply ( null , uint ) ) ;
522+ if ( current_obj === null || typeof current_obj !== "object" || Array . isArray ( current_obj ) ) {
523+ continue ;
525524 }
526- }
527525
528- if ( is_outer ) {
529- // only save if we are at the outermost level
530- localStorage . setItem ( "fs" , JSON . stringify ( state ) ) ;
526+ // iterate over the keys of the current object
527+ for ( const key of Object . keys ( current_obj ) ) {
528+ const value = current_obj [ key ] ;
529+
530+ if ( ! value ) {
531+ continue ;
532+ } else if ( typeof value === "object" && ! Array . isArray ( value ) ) {
533+ // if the value is a nested object, add it to the stack to be processed later (depth first)
534+ stack . push ( value ) ;
535+ } else if ( Array . isArray ( value ) ) {
536+ console . log ( `Migration: converting ${ key } to b64 string` ) ;
537+
538+ try {
539+ const values = value . map ( ( x : string ) => parseInt ( x ) ) ;
540+ const uint = new Uint8Array ( values ) ;
541+ // uint.toBase64() isnt mainstream yet
542+ current_obj [ key ] = btoa ( String . fromCharCode . apply ( null , uint ) ) ;
543+ } catch ( e ) {
544+ console . error ( `Migration failed for key "${ key } ":` , e ) ;
545+ }
546+ }
547+ }
531548 }
549+
550+ // only save after the whole traversal
551+ localStorage . setItem ( "fs" , JSON . stringify ( state ) ) ;
532552}
0 commit comments