* @param {string} path * @returns {string}
(path)
| 984 | * @returns {string} |
| 985 | */ |
| 986 | extname(path) { |
| 987 | validateString(path, 'path'); |
| 988 | let start = 0; |
| 989 | let startDot = -1; |
| 990 | let startPart = 0; |
| 991 | let end = -1; |
| 992 | let matchedSlash = true; |
| 993 | // Track the state of characters (if any) we see before our first dot and |
| 994 | // after any path separator we find |
| 995 | let preDotState = 0; |
| 996 | |
| 997 | // Check for a drive letter prefix so as not to mistake the following |
| 998 | // path separator as an extra separator at the end of the path that can be |
| 999 | // disregarded |
| 1000 | |
| 1001 | if (path.length >= 2 && |
| 1002 | StringPrototypeCharCodeAt(path, 1) === CHAR_COLON && |
| 1003 | isWindowsDeviceRoot(StringPrototypeCharCodeAt(path, 0))) { |
| 1004 | start = startPart = 2; |
| 1005 | } |
| 1006 | |
| 1007 | for (let i = path.length - 1; i >= start; --i) { |
| 1008 | const code = StringPrototypeCharCodeAt(path, i); |
| 1009 | if (isPathSeparator(code)) { |
| 1010 | // If we reached a path separator that was not part of a set of path |
| 1011 | // separators at the end of the string, stop now |
| 1012 | if (!matchedSlash) { |
| 1013 | startPart = i + 1; |
| 1014 | break; |
| 1015 | } |
| 1016 | continue; |
| 1017 | } |
| 1018 | if (end === -1) { |
| 1019 | // We saw the first non-path separator, mark this as the end of our |
| 1020 | // extension |
| 1021 | matchedSlash = false; |
| 1022 | end = i + 1; |
| 1023 | } |
| 1024 | if (code === CHAR_DOT) { |
| 1025 | // If this is our first dot, mark it as the start of our extension |
| 1026 | if (startDot === -1) |
| 1027 | startDot = i; |
| 1028 | else if (preDotState !== 1) |
| 1029 | preDotState = 1; |
| 1030 | } else if (startDot !== -1) { |
| 1031 | // We saw a non-dot and non-path separator before our dot, so we should |
| 1032 | // have a good chance at having a non-empty extension |
| 1033 | preDotState = -1; |
| 1034 | } |
| 1035 | } |
| 1036 | |
| 1037 | if (startDot === -1 || |
| 1038 | end === -1 || |
| 1039 | // We saw a non-dot character immediately before the dot |
| 1040 | preDotState === 0 || |
| 1041 | // The (right-most) trimmed path component is exactly '..' |
| 1042 | (preDotState === 1 && |
| 1043 | startDot === end - 1 && |
no test coverage detected
searching dependent graphs…