@@ -1496,25 +1496,27 @@ const backslashRegEx = /\\/g;
1496
1496
const newlineRegEx = / \n / g;
1497
1497
const carriageReturnRegEx = / \r / g;
1498
1498
const tabRegEx = / \t / g;
1499
+ const questionRegex = / \? / g;
1500
+ const hashRegex = / # / g;
1499
1501
1500
1502
function encodePathChars ( filepath ) {
1501
- if ( StringPrototypeIncludes ( filepath , '%' ) )
1503
+ if ( StringPrototypeIndexOf ( filepath , '%' ) !== - 1 )
1502
1504
filepath = RegExpPrototypeSymbolReplace ( percentRegEx , filepath , '%25' ) ;
1503
1505
// In posix, backslash is a valid character in paths:
1504
- if ( ! isWindows && StringPrototypeIncludes ( filepath , '\\' ) )
1506
+ if ( ! isWindows && StringPrototypeIndexOf ( filepath , '\\' ) !== - 1 )
1505
1507
filepath = RegExpPrototypeSymbolReplace ( backslashRegEx , filepath , '%5C' ) ;
1506
- if ( StringPrototypeIncludes ( filepath , '\n' ) )
1508
+ if ( StringPrototypeIndexOf ( filepath , '\n' ) !== - 1 )
1507
1509
filepath = RegExpPrototypeSymbolReplace ( newlineRegEx , filepath , '%0A' ) ;
1508
- if ( StringPrototypeIncludes ( filepath , '\r' ) )
1510
+ if ( StringPrototypeIndexOf ( filepath , '\r' ) !== - 1 )
1509
1511
filepath = RegExpPrototypeSymbolReplace ( carriageReturnRegEx , filepath , '%0D' ) ;
1510
- if ( StringPrototypeIncludes ( filepath , '\t' ) )
1512
+ if ( StringPrototypeIndexOf ( filepath , '\t' ) !== - 1 )
1511
1513
filepath = RegExpPrototypeSymbolReplace ( tabRegEx , filepath , '%09' ) ;
1512
1514
return filepath ;
1513
1515
}
1514
1516
1515
1517
function pathToFileURL ( filepath ) {
1516
- const outURL = new URL ( 'file://' ) ;
1517
1518
if ( isWindows && StringPrototypeStartsWith ( filepath , '\\\\' ) ) {
1519
+ const outURL = new URL ( 'file://' ) ;
1518
1520
// UNC path format: \\server\share\resource
1519
1521
const hostnameEndIndex = StringPrototypeIndexOf ( filepath , '\\' , 2 ) ;
1520
1522
if ( hostnameEndIndex === - 1 ) {
@@ -1535,18 +1537,29 @@ function pathToFileURL(filepath) {
1535
1537
outURL . hostname = domainToASCII ( hostname ) ;
1536
1538
outURL . pathname = encodePathChars (
1537
1539
RegExpPrototypeSymbolReplace ( backslashRegEx , StringPrototypeSlice ( filepath , hostnameEndIndex ) , '/' ) ) ;
1538
- } else {
1539
- let resolved = path . resolve ( filepath ) ;
1540
- // path.resolve strips trailing slashes so we must add them back
1541
- const filePathLast = StringPrototypeCharCodeAt ( filepath ,
1542
- filepath . length - 1 ) ;
1543
- if ( ( filePathLast === CHAR_FORWARD_SLASH ||
1544
- ( isWindows && filePathLast === CHAR_BACKWARD_SLASH ) ) &&
1545
- resolved [ resolved . length - 1 ] !== path . sep )
1546
- resolved += '/' ;
1547
- outURL . pathname = encodePathChars ( resolved ) ;
1540
+ return outURL ;
1548
1541
}
1549
- return outURL ;
1542
+ let resolved = path . resolve ( filepath ) ;
1543
+ // path.resolve strips trailing slashes so we must add them back
1544
+ const filePathLast = StringPrototypeCharCodeAt ( filepath ,
1545
+ filepath . length - 1 ) ;
1546
+ if ( ( filePathLast === CHAR_FORWARD_SLASH ||
1547
+ ( isWindows && filePathLast === CHAR_BACKWARD_SLASH ) ) &&
1548
+ resolved [ resolved . length - 1 ] !== path . sep )
1549
+ resolved += '/' ;
1550
+
1551
+ // Call encodePathChars first to avoid encoding % again for ? and #.
1552
+ resolved = encodePathChars ( resolved ) ;
1553
+
1554
+ // Question and hash character should be included in pathname.
1555
+ // Therefore, encoding is required to eliminate parsing them in different states.
1556
+ // This is done as an optimization to not creating a URL instance and
1557
+ // later triggering pathname setter, which impacts performance
1558
+ if ( StringPrototypeIndexOf ( resolved , '?' ) !== - 1 )
1559
+ resolved = RegExpPrototypeSymbolReplace ( questionRegex , resolved , '%3F' ) ;
1560
+ if ( StringPrototypeIndexOf ( resolved , '#' ) !== - 1 )
1561
+ resolved = RegExpPrototypeSymbolReplace ( hashRegex , resolved , '%23' ) ;
1562
+ return new URL ( `file://${ resolved } ` ) ;
1550
1563
}
1551
1564
1552
1565
function toPathIfFileURL ( fileURLOrPath ) {
0 commit comments