@@ -464,86 +464,67 @@ const win32 = {
464464 from . charCodeAt ( fromEnd - 1 ) === CHAR_BACKWARD_SLASH ) {
465465 fromEnd -- ;
466466 }
467- const fromLen = fromEnd - fromStart ;
467+ if ( fromStart > 0 || fromEnd < from . length )
468+ from = from . slice ( fromStart , fromEnd ) ;
468469
469470 // Trim any leading backslashes
471+ const toLenBeforeTrim = to . length ;
470472 let toStart = 0 ;
471- while ( toStart < to . length &&
473+ while ( toStart < toLenBeforeTrim &&
472474 to . charCodeAt ( toStart ) === CHAR_BACKWARD_SLASH ) {
473475 toStart ++ ;
474476 }
475477 // Trim trailing backslashes (applicable to UNC paths only)
476- let toEnd = to . length ;
478+ let toEnd = toLenBeforeTrim ;
477479 while ( toEnd - 1 > toStart &&
478480 to . charCodeAt ( toEnd - 1 ) === CHAR_BACKWARD_SLASH ) {
479481 toEnd -- ;
480482 }
481- const toLen = toEnd - toStart ;
483+ if ( toStart > 0 || toEnd < toLenBeforeTrim )
484+ to = to . slice ( toStart , toEnd ) ;
485+
486+ // Even the device roots are different. Return the original `to`.
487+ if ( from . charCodeAt ( 0 ) !== to . charCodeAt ( 0 ) )
488+ return toOrig ;
489+
490+ // Split paths
491+ const fromParts = from . split ( '\\' ) ;
492+ const toParts = to . split ( '\\' ) ;
482493
483- // Compare paths to find the longest common path from root
484- const length = fromLen < toLen ? fromLen : toLen ;
485- let lastCommonSep = - 1 ;
486494 let i = 0 ;
487- for ( ; i < length ; i ++ ) {
488- const fromCode = from . charCodeAt ( fromStart + i ) ;
489- if ( fromCode !== to . charCodeAt ( toStart + i ) )
490- break ;
491- else if ( fromCode === CHAR_BACKWARD_SLASH )
492- lastCommonSep = i ;
493- }
495+ const partLen = fromParts . length < toParts . length ?
496+ fromParts . length :
497+ toParts . length ;
494498
495- // We found a mismatch before the first common path separator was seen, so
496- // return the original `to`.
497- if ( i !== length ) {
498- if ( lastCommonSep === - 1 )
499- return toOrig ;
500- } else {
501- if ( toLen > length ) {
502- if ( to . charCodeAt ( toStart + i ) === CHAR_BACKWARD_SLASH ) {
503- // We get here if `from` is the exact base path for `to`.
504- // For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz'
505- return toOrig . slice ( toStart + i + 1 ) ;
506- }
507- if ( i === 2 ) {
508- // We get here if `from` is the device root.
509- // For example: from='C:\\'; to='C:\\foo'
510- return toOrig . slice ( toStart + i ) ;
511- }
512- }
513- if ( fromLen > length ) {
514- if ( from . charCodeAt ( fromStart + i ) === CHAR_BACKWARD_SLASH ) {
515- // We get here if `to` is the exact base path for `from`.
516- // For example: from='C:\\foo\\bar'; to='C:\\foo'
517- lastCommonSep = i ;
518- } else if ( i === 2 ) {
519- // We get here if `to` is the device root.
520- // For example: from='C:\\foo\\bar'; to='C:\\'
521- lastCommonSep = 3 ;
522- }
523- }
524- if ( lastCommonSep === - 1 )
525- lastCommonSep = 0 ;
526- }
499+ // Find the number of common ancestors
500+ while ( i < partLen && fromParts [ i ] === toParts [ i ] )
501+ i ++ ;
527502
503+ const numOfCommonAncestors = i ;
504+ let numOfStepsToWalkUp = fromParts . length - numOfCommonAncestors ;
528505 let out = '' ;
529- // Generate the relative path based on the path difference between `to` and
530- // `from`
531- for ( i = fromStart + lastCommonSep + 1 ; i <= fromEnd ; ++ i ) {
532- if ( i === fromEnd || from . charCodeAt ( i ) === CHAR_BACKWARD_SLASH ) {
533- out += out . length === 0 ? '..' : '\\..' ;
534- }
535- }
536506
537- toStart += lastCommonSep ;
507+ // Walk up the directory tree to get the nearest common ancestor (if any)
508+ // and then append the "different" parts (if any)
509+ while ( numOfStepsToWalkUp -- > 0 )
510+ out += out . length === 0 ? '..' : '\\..' ;
538511
539- // Lastly, append the rest of the destination (`to`) path that comes after
540- // the common path parts
541- if ( out . length > 0 )
542- return `${ out } ${ toOrig . slice ( toStart , toEnd ) } ` ;
512+ let partIx = 0 ;
513+
514+ // Find the starting position of the remaining part
515+ const toOrigEnd = toOrig . length - toLenBeforeTrim + toEnd ;
516+ for ( i = toStart ; partIx < numOfCommonAncestors && i <= toOrigEnd ; i ++ )
517+ if ( toOrig . charCodeAt ( i ) === CHAR_BACKWARD_SLASH )
518+ partIx ++ ;
519+
520+ if ( partIx > 0 && i <= toOrigEnd ) {
521+ if ( out . length > 0 )
522+ out += '\\' ;
523+
524+ out += toOrig . slice ( i , toOrigEnd ) ;
525+ }
543526
544- if ( toOrig . charCodeAt ( toStart ) === CHAR_BACKWARD_SLASH )
545- ++ toStart ;
546- return toOrig . slice ( toStart , toEnd ) ;
527+ return out ;
547528 } ,
548529
549530 toNamespacedPath ( path ) {
0 commit comments