(path: string)
| 850 | }, |
| 851 | |
| 852 | extname(path: string): string { |
| 853 | validateString(path, 'path'); |
| 854 | let start = 0; |
| 855 | let startDot = -1; |
| 856 | let startPart = 0; |
| 857 | let end = -1; |
| 858 | let matchedSlash = true; |
| 859 | // Track the state of characters (if any) we see before our first dot and |
| 860 | // after any path separator we find |
| 861 | let preDotState = 0; |
| 862 | |
| 863 | // Check for a drive letter prefix so as not to mistake the following |
| 864 | // path separator as an extra separator at the end of the path that can be |
| 865 | // disregarded |
| 866 | |
| 867 | if (path.length >= 2 && path.charCodeAt(1) === CHAR_COLON && isWindowsDeviceRoot(path.charCodeAt(0))) { |
| 868 | start = startPart = 2; |
| 869 | } |
| 870 | |
| 871 | for (let i = path.length - 1; i >= start; --i) { |
| 872 | const code = path.charCodeAt(i); |
| 873 | if (isPathSeparator(code)) { |
| 874 | // If we reached a path separator that was not part of a set of path |
| 875 | // separators at the end of the string, stop now |
| 876 | if (!matchedSlash) { |
| 877 | startPart = i + 1; |
| 878 | break; |
| 879 | } |
| 880 | continue; |
| 881 | } |
| 882 | if (end === -1) { |
| 883 | // We saw the first non-path separator, mark this as the end of our |
| 884 | // extension |
| 885 | matchedSlash = false; |
| 886 | end = i + 1; |
| 887 | } |
| 888 | if (code === CHAR_DOT) { |
| 889 | // If this is our first dot, mark it as the start of our extension |
| 890 | if (startDot === -1) { |
| 891 | startDot = i; |
| 892 | } else if (preDotState !== 1) { |
| 893 | preDotState = 1; |
| 894 | } |
| 895 | } else if (startDot !== -1) { |
| 896 | // We saw a non-dot and non-path separator before our dot, so we should |
| 897 | // have a good chance at having a non-empty extension |
| 898 | preDotState = -1; |
| 899 | } |
| 900 | } |
| 901 | |
| 902 | if ( |
| 903 | startDot === -1 || |
| 904 | end === -1 || |
| 905 | // We saw a non-dot character immediately before the dot |
| 906 | preDotState === 0 || |
| 907 | // The (right-most) trimmed path component is exactly '..' |
| 908 | (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) |
| 909 | ) { |
nothing calls this directly
no test coverage detected