@@ -27,6 +27,9 @@ const {
27
27
ObjectAssign,
28
28
ObjectKeys,
29
29
StringPrototypeCharCodeAt,
30
+ StringPrototypeIndexOf,
31
+ StringPrototypeReplaceAll,
32
+ StringPrototypeSlice,
30
33
decodeURIComponent,
31
34
} = primordials ;
32
35
@@ -637,6 +640,10 @@ Url.prototype.format = function format() {
637
640
}
638
641
639
642
let protocol = this . protocol || '' ;
643
+ if ( protocol && StringPrototypeCharCodeAt ( protocol , protocol . length - 1 ) !== 58 /* : */ ) {
644
+ protocol += ':' ;
645
+ }
646
+
640
647
let pathname = this . pathname || '' ;
641
648
let hash = this . hash || '' ;
642
649
let host = '' ;
@@ -646,7 +653,7 @@ Url.prototype.format = function format() {
646
653
host = auth + this . host ;
647
654
} else if ( this . hostname ) {
648
655
host = auth + (
649
- this . hostname . includes ( ':' ) && ! isIpv6Hostname ( this . hostname ) ?
656
+ StringPrototypeIndexOf ( this . hostname , ':' ) !== - 1 && ! isIpv6Hostname ( this . hostname ) ?
650
657
'[' + this . hostname + ']' :
651
658
this . hostname
652
659
) ;
@@ -658,59 +665,55 @@ Url.prototype.format = function format() {
658
665
if ( this . query !== null && typeof this . query === 'object' ) {
659
666
query = querystring . stringify ( this . query ) ;
660
667
}
661
-
662
668
let search = this . search || ( query && ( '?' + query ) ) || '' ;
663
669
664
- if ( protocol && protocol . charCodeAt ( protocol . length - 1 ) !== 58 /* : */ )
665
- protocol += ':' ;
666
-
667
- let newPathname = '' ;
668
- let lastPos = 0 ;
669
- for ( let i = 0 ; i < pathname . length ; ++ i ) {
670
- switch ( pathname . charCodeAt ( i ) ) {
671
- case CHAR_HASH :
672
- if ( i - lastPos > 0 )
673
- newPathname += pathname . slice ( lastPos , i ) ;
674
- newPathname += '%23' ;
675
- lastPos = i + 1 ;
676
- break ;
677
- case CHAR_QUESTION_MARK :
678
- if ( i - lastPos > 0 )
679
- newPathname += pathname . slice ( lastPos , i ) ;
680
- newPathname += '%3F' ;
670
+ if ( StringPrototypeIndexOf ( pathname , '#' ) !== - 1 || StringPrototypeIndexOf ( pathname , '?' ) !== - 1 ) {
671
+ let newPathname = '' ;
672
+ let lastPos = 0 ;
673
+ const len = pathname . length ;
674
+ for ( let i = 0 ; i < len ; i ++ ) {
675
+ const code = StringPrototypeCharCodeAt ( pathname , i ) ;
676
+ if ( code === CHAR_HASH || code === CHAR_QUESTION_MARK ) {
677
+ if ( i > lastPos ) {
678
+ newPathname += StringPrototypeSlice ( pathname , lastPos , i ) ;
679
+ }
680
+ newPathname += ( code === CHAR_HASH ? '%23' : '%3F' ) ;
681
681
lastPos = i + 1 ;
682
- break ;
682
+ }
683
683
}
684
- }
685
- if ( lastPos > 0 ) {
686
- if ( lastPos !== pathname . length )
687
- pathname = newPathname + pathname . slice ( lastPos ) ;
688
- else
689
- pathname = newPathname ;
684
+ if ( lastPos < len ) {
685
+ newPathname += StringPrototypeSlice ( pathname , lastPos ) ;
686
+ }
687
+ pathname = newPathname ;
690
688
}
691
689
692
690
// Only the slashedProtocols get the //. Not mailto:, xmpp:, etc.
693
691
// unless they had them to begin with.
694
692
if ( this . slashes || slashedProtocol . has ( protocol ) ) {
695
693
if ( this . slashes || host ) {
696
- if ( pathname && pathname . charCodeAt ( 0 ) !== CHAR_FORWARD_SLASH )
694
+ if ( pathname && StringPrototypeCharCodeAt ( pathname , 0 ) !== CHAR_FORWARD_SLASH )
697
695
pathname = '/' + pathname ;
698
696
host = '//' + host ;
699
697
} else if ( protocol . length >= 4 &&
700
- protocol . charCodeAt ( 0 ) === 102 /* f */ &&
701
- protocol . charCodeAt ( 1 ) === 105 /* i */ &&
702
- protocol . charCodeAt ( 2 ) === 108 /* l */ &&
703
- protocol . charCodeAt ( 3 ) === 101 /* e */ ) {
698
+ StringPrototypeCharCodeAt ( protocol , 0 ) === 102 /* f */ &&
699
+ StringPrototypeCharCodeAt ( protocol , 1 ) === 105 /* i */ &&
700
+ StringPrototypeCharCodeAt ( protocol , 2 ) === 108 /* l */ &&
701
+ StringPrototypeCharCodeAt ( protocol , 3 ) === 101 /* e */ ) {
704
702
host = '//' ;
705
703
}
706
704
}
707
705
708
- search = search . replaceAll ( '#' , '%23' ) ;
706
+ // Escape '#' in search.
707
+ if ( StringPrototypeIndexOf ( search , '#' ) !== - 1 ) {
708
+ search = StringPrototypeReplaceAll ( search , '#' , '%23' ) ;
709
+ }
709
710
710
- if ( hash && hash . charCodeAt ( 0 ) !== CHAR_HASH )
711
+ if ( hash && StringPrototypeCharCodeAt ( hash , 0 ) !== CHAR_HASH ) {
711
712
hash = '#' + hash ;
712
- if ( search && search . charCodeAt ( 0 ) !== CHAR_QUESTION_MARK )
713
+ }
714
+ if ( search && StringPrototypeCharCodeAt ( search , 0 ) !== CHAR_QUESTION_MARK ) {
713
715
search = '?' + search ;
716
+ }
714
717
715
718
return protocol + host + pathname + search + hash ;
716
719
} ;
0 commit comments