@@ -1422,25 +1422,27 @@ const backslashRegEx = /\\/g;
1422
1422
const newlineRegEx = / \n / g;
1423
1423
const carriageReturnRegEx = / \r / g;
1424
1424
const tabRegEx = / \t / g;
1425
+ const questionRegex = / \? / g;
1426
+ const hashRegex = / # / g;
1425
1427
1426
1428
function encodePathChars ( filepath ) {
1427
- if ( StringPrototypeIncludes ( filepath , '%' ) )
1429
+ if ( StringPrototypeIndexOf ( filepath , '%' ) !== - 1 )
1428
1430
filepath = RegExpPrototypeSymbolReplace ( percentRegEx , filepath , '%25' ) ;
1429
1431
// In posix, backslash is a valid character in paths:
1430
- if ( ! isWindows && StringPrototypeIncludes ( filepath , '\\' ) )
1432
+ if ( ! isWindows && StringPrototypeIndexOf ( filepath , '\\' ) !== - 1 )
1431
1433
filepath = RegExpPrototypeSymbolReplace ( backslashRegEx , filepath , '%5C' ) ;
1432
- if ( StringPrototypeIncludes ( filepath , '\n' ) )
1434
+ if ( StringPrototypeIndexOf ( filepath , '\n' ) !== - 1 )
1433
1435
filepath = RegExpPrototypeSymbolReplace ( newlineRegEx , filepath , '%0A' ) ;
1434
- if ( StringPrototypeIncludes ( filepath , '\r' ) )
1436
+ if ( StringPrototypeIndexOf ( filepath , '\r' ) !== - 1 )
1435
1437
filepath = RegExpPrototypeSymbolReplace ( carriageReturnRegEx , filepath , '%0D' ) ;
1436
- if ( StringPrototypeIncludes ( filepath , '\t' ) )
1438
+ if ( StringPrototypeIndexOf ( filepath , '\t' ) !== - 1 )
1437
1439
filepath = RegExpPrototypeSymbolReplace ( tabRegEx , filepath , '%09' ) ;
1438
1440
return filepath ;
1439
1441
}
1440
1442
1441
1443
function pathToFileURL ( filepath ) {
1442
- const outURL = new URL ( 'file://' ) ;
1443
1444
if ( isWindows && StringPrototypeStartsWith ( filepath , '\\\\' ) ) {
1445
+ const outURL = new URL ( 'file://' ) ;
1444
1446
// UNC path format: \\server\share\resource
1445
1447
const hostnameEndIndex = StringPrototypeIndexOf ( filepath , '\\' , 2 ) ;
1446
1448
if ( hostnameEndIndex === - 1 ) {
@@ -1461,18 +1463,29 @@ function pathToFileURL(filepath) {
1461
1463
outURL . hostname = domainToASCII ( hostname ) ;
1462
1464
outURL . pathname = encodePathChars (
1463
1465
RegExpPrototypeSymbolReplace ( backslashRegEx , StringPrototypeSlice ( filepath , hostnameEndIndex ) , '/' ) ) ;
1464
- } else {
1465
- let resolved = path . resolve ( filepath ) ;
1466
- // path.resolve strips trailing slashes so we must add them back
1467
- const filePathLast = StringPrototypeCharCodeAt ( filepath ,
1468
- filepath . length - 1 ) ;
1469
- if ( ( filePathLast === CHAR_FORWARD_SLASH ||
1470
- ( isWindows && filePathLast === CHAR_BACKWARD_SLASH ) ) &&
1471
- resolved [ resolved . length - 1 ] !== path . sep )
1472
- resolved += '/' ;
1473
- outURL . pathname = encodePathChars ( resolved ) ;
1474
- }
1475
- return outURL ;
1466
+ return outURL ;
1467
+ }
1468
+ let resolved = path . resolve ( filepath ) ;
1469
+ // path.resolve strips trailing slashes so we must add them back
1470
+ const filePathLast = StringPrototypeCharCodeAt ( filepath ,
1471
+ filepath . length - 1 ) ;
1472
+ if ( ( filePathLast === CHAR_FORWARD_SLASH ||
1473
+ ( isWindows && filePathLast === CHAR_BACKWARD_SLASH ) ) &&
1474
+ resolved [ resolved . length - 1 ] !== path . sep )
1475
+ resolved += '/' ;
1476
+
1477
+ // Call encodePathChars first to avoid encoding % again for ? and #.
1478
+ resolved = encodePathChars ( resolved ) ;
1479
+
1480
+ // Question and hash character should be included in pathname.
1481
+ // Therefore, encoding is required to eliminate parsing them in different states.
1482
+ // This is done as an optimization to not creating a URL instance and
1483
+ // later triggering pathname setter, which impacts performance
1484
+ if ( StringPrototypeIndexOf ( resolved , '?' ) !== - 1 )
1485
+ resolved = RegExpPrototypeSymbolReplace ( questionRegex , resolved , '%3F' ) ;
1486
+ if ( StringPrototypeIndexOf ( resolved , '#' ) !== - 1 )
1487
+ resolved = RegExpPrototypeSymbolReplace ( hashRegex , resolved , '%23' ) ;
1488
+ return new URL ( `file://${ resolved } ` ) ;
1476
1489
}
1477
1490
1478
1491
function toPathIfFileURL ( fileURLOrPath ) {
0 commit comments