(path: string)
| 432 | }; |
| 433 | |
| 434 | const extname = function extname(path: string) { |
| 435 | assertPath(path); |
| 436 | let startDot = -1; |
| 437 | let startPart = 0; |
| 438 | let end = -1; |
| 439 | let matchedSlash = true; |
| 440 | // Track the state of characters (if any) we see before our first dot and |
| 441 | // after any path separator we find |
| 442 | let preDotState = 0; |
| 443 | for (let i = path.length - 1; i >= 0; --i) { |
| 444 | const code = path.charCodeAt(i); |
| 445 | if (code === 47 /*/*/) { |
| 446 | // If we reached a path separator that was not part of a set of path |
| 447 | // separators at the end of the string, stop now |
| 448 | if (!matchedSlash) { |
| 449 | startPart = i + 1; |
| 450 | break; |
| 451 | } |
| 452 | continue; |
| 453 | } |
| 454 | if (end === -1) { |
| 455 | // We saw the first non-path separator, mark this as the end of our |
| 456 | // extension |
| 457 | matchedSlash = false; |
| 458 | end = i + 1; |
| 459 | } |
| 460 | if (code === 46 /*.*/) { |
| 461 | // If this is our first dot, mark it as the start of our extension |
| 462 | if (startDot === -1) { |
| 463 | startDot = i; |
| 464 | } else if (preDotState !== 1) { |
| 465 | preDotState = 1; |
| 466 | } |
| 467 | } else if (startDot !== -1) { |
| 468 | // We saw a non-dot and non-path separator before our dot, so we should |
| 469 | // have a good chance at having a non-empty extension |
| 470 | preDotState = -1; |
| 471 | } |
| 472 | } |
| 473 | |
| 474 | if ( |
| 475 | startDot === -1 || |
| 476 | end === -1 || |
| 477 | // We saw a non-dot character immediately before the dot |
| 478 | preDotState === 0 || |
| 479 | // The (right-most) trimmed path component is exactly '..' |
| 480 | (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) |
| 481 | ) { |
| 482 | return ''; |
| 483 | } |
| 484 | return path.slice(startDot, end); |
| 485 | }; |
| 486 | |
| 487 | const format = function format(pathObject: FormatInputPathObject) { |
| 488 | if (pathObject === null || typeof pathObject !== 'object') { |
no test coverage detected
searching dependent graphs…