11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors.
21cb0ef41Sopenharmony_ci//
31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a
41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the
51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including
61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish,
71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit
81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the
91cb0ef41Sopenharmony_ci// following conditions:
101cb0ef41Sopenharmony_ci//
111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included
121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software.
131cb0ef41Sopenharmony_ci//
141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE.
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci'use strict';
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ciconst {
251cb0ef41Sopenharmony_ci  FunctionPrototypeBind,
261cb0ef41Sopenharmony_ci  StringPrototypeCharCodeAt,
271cb0ef41Sopenharmony_ci  StringPrototypeIndexOf,
281cb0ef41Sopenharmony_ci  StringPrototypeLastIndexOf,
291cb0ef41Sopenharmony_ci  StringPrototypeReplace,
301cb0ef41Sopenharmony_ci  StringPrototypeSlice,
311cb0ef41Sopenharmony_ci  StringPrototypeToLowerCase,
321cb0ef41Sopenharmony_ci} = primordials;
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ciconst {
351cb0ef41Sopenharmony_ci  CHAR_UPPERCASE_A,
361cb0ef41Sopenharmony_ci  CHAR_LOWERCASE_A,
371cb0ef41Sopenharmony_ci  CHAR_UPPERCASE_Z,
381cb0ef41Sopenharmony_ci  CHAR_LOWERCASE_Z,
391cb0ef41Sopenharmony_ci  CHAR_DOT,
401cb0ef41Sopenharmony_ci  CHAR_FORWARD_SLASH,
411cb0ef41Sopenharmony_ci  CHAR_BACKWARD_SLASH,
421cb0ef41Sopenharmony_ci  CHAR_COLON,
431cb0ef41Sopenharmony_ci  CHAR_QUESTION_MARK,
441cb0ef41Sopenharmony_ci} = require('internal/constants');
451cb0ef41Sopenharmony_ciconst {
461cb0ef41Sopenharmony_ci  validateObject,
471cb0ef41Sopenharmony_ci  validateString,
481cb0ef41Sopenharmony_ci} = require('internal/validators');
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ciconst platformIsWin32 = (process.platform === 'win32');
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_cifunction isPathSeparator(code) {
531cb0ef41Sopenharmony_ci  return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
541cb0ef41Sopenharmony_ci}
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_cifunction isPosixPathSeparator(code) {
571cb0ef41Sopenharmony_ci  return code === CHAR_FORWARD_SLASH;
581cb0ef41Sopenharmony_ci}
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_cifunction isWindowsDeviceRoot(code) {
611cb0ef41Sopenharmony_ci  return (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) ||
621cb0ef41Sopenharmony_ci         (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z);
631cb0ef41Sopenharmony_ci}
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci// Resolves . and .. elements in a path with directory names
661cb0ef41Sopenharmony_cifunction normalizeString(path, allowAboveRoot, separator, isPathSeparator) {
671cb0ef41Sopenharmony_ci  let res = '';
681cb0ef41Sopenharmony_ci  let lastSegmentLength = 0;
691cb0ef41Sopenharmony_ci  let lastSlash = -1;
701cb0ef41Sopenharmony_ci  let dots = 0;
711cb0ef41Sopenharmony_ci  let code = 0;
721cb0ef41Sopenharmony_ci  for (let i = 0; i <= path.length; ++i) {
731cb0ef41Sopenharmony_ci    if (i < path.length)
741cb0ef41Sopenharmony_ci      code = StringPrototypeCharCodeAt(path, i);
751cb0ef41Sopenharmony_ci    else if (isPathSeparator(code))
761cb0ef41Sopenharmony_ci      break;
771cb0ef41Sopenharmony_ci    else
781cb0ef41Sopenharmony_ci      code = CHAR_FORWARD_SLASH;
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci    if (isPathSeparator(code)) {
811cb0ef41Sopenharmony_ci      if (lastSlash === i - 1 || dots === 1) {
821cb0ef41Sopenharmony_ci        // NOOP
831cb0ef41Sopenharmony_ci      } else if (dots === 2) {
841cb0ef41Sopenharmony_ci        if (res.length < 2 || lastSegmentLength !== 2 ||
851cb0ef41Sopenharmony_ci            StringPrototypeCharCodeAt(res, res.length - 1) !== CHAR_DOT ||
861cb0ef41Sopenharmony_ci            StringPrototypeCharCodeAt(res, res.length - 2) !== CHAR_DOT) {
871cb0ef41Sopenharmony_ci          if (res.length > 2) {
881cb0ef41Sopenharmony_ci            const lastSlashIndex = StringPrototypeLastIndexOf(res, separator);
891cb0ef41Sopenharmony_ci            if (lastSlashIndex === -1) {
901cb0ef41Sopenharmony_ci              res = '';
911cb0ef41Sopenharmony_ci              lastSegmentLength = 0;
921cb0ef41Sopenharmony_ci            } else {
931cb0ef41Sopenharmony_ci              res = StringPrototypeSlice(res, 0, lastSlashIndex);
941cb0ef41Sopenharmony_ci              lastSegmentLength =
951cb0ef41Sopenharmony_ci                res.length - 1 - StringPrototypeLastIndexOf(res, separator);
961cb0ef41Sopenharmony_ci            }
971cb0ef41Sopenharmony_ci            lastSlash = i;
981cb0ef41Sopenharmony_ci            dots = 0;
991cb0ef41Sopenharmony_ci            continue;
1001cb0ef41Sopenharmony_ci          } else if (res.length !== 0) {
1011cb0ef41Sopenharmony_ci            res = '';
1021cb0ef41Sopenharmony_ci            lastSegmentLength = 0;
1031cb0ef41Sopenharmony_ci            lastSlash = i;
1041cb0ef41Sopenharmony_ci            dots = 0;
1051cb0ef41Sopenharmony_ci            continue;
1061cb0ef41Sopenharmony_ci          }
1071cb0ef41Sopenharmony_ci        }
1081cb0ef41Sopenharmony_ci        if (allowAboveRoot) {
1091cb0ef41Sopenharmony_ci          res += res.length > 0 ? `${separator}..` : '..';
1101cb0ef41Sopenharmony_ci          lastSegmentLength = 2;
1111cb0ef41Sopenharmony_ci        }
1121cb0ef41Sopenharmony_ci      } else {
1131cb0ef41Sopenharmony_ci        if (res.length > 0)
1141cb0ef41Sopenharmony_ci          res += `${separator}${StringPrototypeSlice(path, lastSlash + 1, i)}`;
1151cb0ef41Sopenharmony_ci        else
1161cb0ef41Sopenharmony_ci          res = StringPrototypeSlice(path, lastSlash + 1, i);
1171cb0ef41Sopenharmony_ci        lastSegmentLength = i - lastSlash - 1;
1181cb0ef41Sopenharmony_ci      }
1191cb0ef41Sopenharmony_ci      lastSlash = i;
1201cb0ef41Sopenharmony_ci      dots = 0;
1211cb0ef41Sopenharmony_ci    } else if (code === CHAR_DOT && dots !== -1) {
1221cb0ef41Sopenharmony_ci      ++dots;
1231cb0ef41Sopenharmony_ci    } else {
1241cb0ef41Sopenharmony_ci      dots = -1;
1251cb0ef41Sopenharmony_ci    }
1261cb0ef41Sopenharmony_ci  }
1271cb0ef41Sopenharmony_ci  return res;
1281cb0ef41Sopenharmony_ci}
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci/**
1311cb0ef41Sopenharmony_ci * @param {string} sep
1321cb0ef41Sopenharmony_ci * @param {{
1331cb0ef41Sopenharmony_ci *  dir?: string;
1341cb0ef41Sopenharmony_ci *  root?: string;
1351cb0ef41Sopenharmony_ci *  base?: string;
1361cb0ef41Sopenharmony_ci *  name?: string;
1371cb0ef41Sopenharmony_ci *  ext?: string;
1381cb0ef41Sopenharmony_ci *  }} pathObject
1391cb0ef41Sopenharmony_ci * @returns {string}
1401cb0ef41Sopenharmony_ci */
1411cb0ef41Sopenharmony_cifunction _format(sep, pathObject) {
1421cb0ef41Sopenharmony_ci  validateObject(pathObject, 'pathObject');
1431cb0ef41Sopenharmony_ci  const dir = pathObject.dir || pathObject.root;
1441cb0ef41Sopenharmony_ci  const base = pathObject.base ||
1451cb0ef41Sopenharmony_ci    `${pathObject.name || ''}${pathObject.ext || ''}`;
1461cb0ef41Sopenharmony_ci  if (!dir) {
1471cb0ef41Sopenharmony_ci    return base;
1481cb0ef41Sopenharmony_ci  }
1491cb0ef41Sopenharmony_ci  return dir === pathObject.root ? `${dir}${base}` : `${dir}${sep}${base}`;
1501cb0ef41Sopenharmony_ci}
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ciconst win32 = {
1531cb0ef41Sopenharmony_ci  /**
1541cb0ef41Sopenharmony_ci   * path.resolve([from ...], to)
1551cb0ef41Sopenharmony_ci   * @param {...string} args
1561cb0ef41Sopenharmony_ci   * @returns {string}
1571cb0ef41Sopenharmony_ci   */
1581cb0ef41Sopenharmony_ci  resolve(...args) {
1591cb0ef41Sopenharmony_ci    let resolvedDevice = '';
1601cb0ef41Sopenharmony_ci    let resolvedTail = '';
1611cb0ef41Sopenharmony_ci    let resolvedAbsolute = false;
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci    for (let i = args.length - 1; i >= -1; i--) {
1641cb0ef41Sopenharmony_ci      let path;
1651cb0ef41Sopenharmony_ci      if (i >= 0) {
1661cb0ef41Sopenharmony_ci        path = args[i];
1671cb0ef41Sopenharmony_ci        validateString(path, `paths[${i}]`);
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci        // Skip empty entries
1701cb0ef41Sopenharmony_ci        if (path.length === 0) {
1711cb0ef41Sopenharmony_ci          continue;
1721cb0ef41Sopenharmony_ci        }
1731cb0ef41Sopenharmony_ci      } else if (resolvedDevice.length === 0) {
1741cb0ef41Sopenharmony_ci        path = process.cwd();
1751cb0ef41Sopenharmony_ci      } else {
1761cb0ef41Sopenharmony_ci        // Windows has the concept of drive-specific current working
1771cb0ef41Sopenharmony_ci        // directories. If we've resolved a drive letter but not yet an
1781cb0ef41Sopenharmony_ci        // absolute path, get cwd for that drive, or the process cwd if
1791cb0ef41Sopenharmony_ci        // the drive cwd is not available. We're sure the device is not
1801cb0ef41Sopenharmony_ci        // a UNC path at this points, because UNC paths are always absolute.
1811cb0ef41Sopenharmony_ci        path = process.env[`=${resolvedDevice}`] || process.cwd();
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_ci        // Verify that a cwd was found and that it actually points
1841cb0ef41Sopenharmony_ci        // to our drive. If not, default to the drive's root.
1851cb0ef41Sopenharmony_ci        if (path === undefined ||
1861cb0ef41Sopenharmony_ci            (StringPrototypeToLowerCase(StringPrototypeSlice(path, 0, 2)) !==
1871cb0ef41Sopenharmony_ci            StringPrototypeToLowerCase(resolvedDevice) &&
1881cb0ef41Sopenharmony_ci            StringPrototypeCharCodeAt(path, 2) === CHAR_BACKWARD_SLASH)) {
1891cb0ef41Sopenharmony_ci          path = `${resolvedDevice}\\`;
1901cb0ef41Sopenharmony_ci        }
1911cb0ef41Sopenharmony_ci      }
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci      const len = path.length;
1941cb0ef41Sopenharmony_ci      let rootEnd = 0;
1951cb0ef41Sopenharmony_ci      let device = '';
1961cb0ef41Sopenharmony_ci      let isAbsolute = false;
1971cb0ef41Sopenharmony_ci      const code = StringPrototypeCharCodeAt(path, 0);
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci      // Try to match a root
2001cb0ef41Sopenharmony_ci      if (len === 1) {
2011cb0ef41Sopenharmony_ci        if (isPathSeparator(code)) {
2021cb0ef41Sopenharmony_ci          // `path` contains just a path separator
2031cb0ef41Sopenharmony_ci          rootEnd = 1;
2041cb0ef41Sopenharmony_ci          isAbsolute = true;
2051cb0ef41Sopenharmony_ci        }
2061cb0ef41Sopenharmony_ci      } else if (isPathSeparator(code)) {
2071cb0ef41Sopenharmony_ci        // Possible UNC root
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ci        // If we started with a separator, we know we at least have an
2101cb0ef41Sopenharmony_ci        // absolute path of some kind (UNC or otherwise)
2111cb0ef41Sopenharmony_ci        isAbsolute = true;
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci        if (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) {
2141cb0ef41Sopenharmony_ci          // Matched double path separator at beginning
2151cb0ef41Sopenharmony_ci          let j = 2;
2161cb0ef41Sopenharmony_ci          let last = j;
2171cb0ef41Sopenharmony_ci          // Match 1 or more non-path separators
2181cb0ef41Sopenharmony_ci          while (j < len &&
2191cb0ef41Sopenharmony_ci                 !isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
2201cb0ef41Sopenharmony_ci            j++;
2211cb0ef41Sopenharmony_ci          }
2221cb0ef41Sopenharmony_ci          if (j < len && j !== last) {
2231cb0ef41Sopenharmony_ci            const firstPart = StringPrototypeSlice(path, last, j);
2241cb0ef41Sopenharmony_ci            // Matched!
2251cb0ef41Sopenharmony_ci            last = j;
2261cb0ef41Sopenharmony_ci            // Match 1 or more path separators
2271cb0ef41Sopenharmony_ci            while (j < len &&
2281cb0ef41Sopenharmony_ci                   isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
2291cb0ef41Sopenharmony_ci              j++;
2301cb0ef41Sopenharmony_ci            }
2311cb0ef41Sopenharmony_ci            if (j < len && j !== last) {
2321cb0ef41Sopenharmony_ci              // Matched!
2331cb0ef41Sopenharmony_ci              last = j;
2341cb0ef41Sopenharmony_ci              // Match 1 or more non-path separators
2351cb0ef41Sopenharmony_ci              while (j < len &&
2361cb0ef41Sopenharmony_ci                     !isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
2371cb0ef41Sopenharmony_ci                j++;
2381cb0ef41Sopenharmony_ci              }
2391cb0ef41Sopenharmony_ci              if (j === len || j !== last) {
2401cb0ef41Sopenharmony_ci                // We matched a UNC root
2411cb0ef41Sopenharmony_ci                device =
2421cb0ef41Sopenharmony_ci                  `\\\\${firstPart}\\${StringPrototypeSlice(path, last, j)}`;
2431cb0ef41Sopenharmony_ci                rootEnd = j;
2441cb0ef41Sopenharmony_ci              }
2451cb0ef41Sopenharmony_ci            }
2461cb0ef41Sopenharmony_ci          }
2471cb0ef41Sopenharmony_ci        } else {
2481cb0ef41Sopenharmony_ci          rootEnd = 1;
2491cb0ef41Sopenharmony_ci        }
2501cb0ef41Sopenharmony_ci      } else if (isWindowsDeviceRoot(code) &&
2511cb0ef41Sopenharmony_ci                  StringPrototypeCharCodeAt(path, 1) === CHAR_COLON) {
2521cb0ef41Sopenharmony_ci        // Possible device root
2531cb0ef41Sopenharmony_ci        device = StringPrototypeSlice(path, 0, 2);
2541cb0ef41Sopenharmony_ci        rootEnd = 2;
2551cb0ef41Sopenharmony_ci        if (len > 2 && isPathSeparator(StringPrototypeCharCodeAt(path, 2))) {
2561cb0ef41Sopenharmony_ci          // Treat separator following drive name as an absolute path
2571cb0ef41Sopenharmony_ci          // indicator
2581cb0ef41Sopenharmony_ci          isAbsolute = true;
2591cb0ef41Sopenharmony_ci          rootEnd = 3;
2601cb0ef41Sopenharmony_ci        }
2611cb0ef41Sopenharmony_ci      }
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci      if (device.length > 0) {
2641cb0ef41Sopenharmony_ci        if (resolvedDevice.length > 0) {
2651cb0ef41Sopenharmony_ci          if (StringPrototypeToLowerCase(device) !==
2661cb0ef41Sopenharmony_ci              StringPrototypeToLowerCase(resolvedDevice))
2671cb0ef41Sopenharmony_ci            // This path points to another device so it is not applicable
2681cb0ef41Sopenharmony_ci            continue;
2691cb0ef41Sopenharmony_ci        } else {
2701cb0ef41Sopenharmony_ci          resolvedDevice = device;
2711cb0ef41Sopenharmony_ci        }
2721cb0ef41Sopenharmony_ci      }
2731cb0ef41Sopenharmony_ci
2741cb0ef41Sopenharmony_ci      if (resolvedAbsolute) {
2751cb0ef41Sopenharmony_ci        if (resolvedDevice.length > 0)
2761cb0ef41Sopenharmony_ci          break;
2771cb0ef41Sopenharmony_ci      } else {
2781cb0ef41Sopenharmony_ci        resolvedTail =
2791cb0ef41Sopenharmony_ci          `${StringPrototypeSlice(path, rootEnd)}\\${resolvedTail}`;
2801cb0ef41Sopenharmony_ci        resolvedAbsolute = isAbsolute;
2811cb0ef41Sopenharmony_ci        if (isAbsolute && resolvedDevice.length > 0) {
2821cb0ef41Sopenharmony_ci          break;
2831cb0ef41Sopenharmony_ci        }
2841cb0ef41Sopenharmony_ci      }
2851cb0ef41Sopenharmony_ci    }
2861cb0ef41Sopenharmony_ci
2871cb0ef41Sopenharmony_ci    // At this point the path should be resolved to a full absolute path,
2881cb0ef41Sopenharmony_ci    // but handle relative paths to be safe (might happen when process.cwd()
2891cb0ef41Sopenharmony_ci    // fails)
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci    // Normalize the tail path
2921cb0ef41Sopenharmony_ci    resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\',
2931cb0ef41Sopenharmony_ci                                   isPathSeparator);
2941cb0ef41Sopenharmony_ci
2951cb0ef41Sopenharmony_ci    return resolvedAbsolute ?
2961cb0ef41Sopenharmony_ci      `${resolvedDevice}\\${resolvedTail}` :
2971cb0ef41Sopenharmony_ci      `${resolvedDevice}${resolvedTail}` || '.';
2981cb0ef41Sopenharmony_ci  },
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci  /**
3011cb0ef41Sopenharmony_ci   * @param {string} path
3021cb0ef41Sopenharmony_ci   * @returns {string}
3031cb0ef41Sopenharmony_ci   */
3041cb0ef41Sopenharmony_ci  normalize(path) {
3051cb0ef41Sopenharmony_ci    validateString(path, 'path');
3061cb0ef41Sopenharmony_ci    const len = path.length;
3071cb0ef41Sopenharmony_ci    if (len === 0)
3081cb0ef41Sopenharmony_ci      return '.';
3091cb0ef41Sopenharmony_ci    let rootEnd = 0;
3101cb0ef41Sopenharmony_ci    let device;
3111cb0ef41Sopenharmony_ci    let isAbsolute = false;
3121cb0ef41Sopenharmony_ci    const code = StringPrototypeCharCodeAt(path, 0);
3131cb0ef41Sopenharmony_ci
3141cb0ef41Sopenharmony_ci    // Try to match a root
3151cb0ef41Sopenharmony_ci    if (len === 1) {
3161cb0ef41Sopenharmony_ci      // `path` contains just a single char, exit early to avoid
3171cb0ef41Sopenharmony_ci      // unnecessary work
3181cb0ef41Sopenharmony_ci      return isPosixPathSeparator(code) ? '\\' : path;
3191cb0ef41Sopenharmony_ci    }
3201cb0ef41Sopenharmony_ci    if (isPathSeparator(code)) {
3211cb0ef41Sopenharmony_ci      // Possible UNC root
3221cb0ef41Sopenharmony_ci
3231cb0ef41Sopenharmony_ci      // If we started with a separator, we know we at least have an absolute
3241cb0ef41Sopenharmony_ci      // path of some kind (UNC or otherwise)
3251cb0ef41Sopenharmony_ci      isAbsolute = true;
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ci      if (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) {
3281cb0ef41Sopenharmony_ci        // Matched double path separator at beginning
3291cb0ef41Sopenharmony_ci        let j = 2;
3301cb0ef41Sopenharmony_ci        let last = j;
3311cb0ef41Sopenharmony_ci        // Match 1 or more non-path separators
3321cb0ef41Sopenharmony_ci        while (j < len &&
3331cb0ef41Sopenharmony_ci               !isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
3341cb0ef41Sopenharmony_ci          j++;
3351cb0ef41Sopenharmony_ci        }
3361cb0ef41Sopenharmony_ci        if (j < len && j !== last) {
3371cb0ef41Sopenharmony_ci          const firstPart = StringPrototypeSlice(path, last, j);
3381cb0ef41Sopenharmony_ci          // Matched!
3391cb0ef41Sopenharmony_ci          last = j;
3401cb0ef41Sopenharmony_ci          // Match 1 or more path separators
3411cb0ef41Sopenharmony_ci          while (j < len &&
3421cb0ef41Sopenharmony_ci                 isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
3431cb0ef41Sopenharmony_ci            j++;
3441cb0ef41Sopenharmony_ci          }
3451cb0ef41Sopenharmony_ci          if (j < len && j !== last) {
3461cb0ef41Sopenharmony_ci            // Matched!
3471cb0ef41Sopenharmony_ci            last = j;
3481cb0ef41Sopenharmony_ci            // Match 1 or more non-path separators
3491cb0ef41Sopenharmony_ci            while (j < len &&
3501cb0ef41Sopenharmony_ci                   !isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
3511cb0ef41Sopenharmony_ci              j++;
3521cb0ef41Sopenharmony_ci            }
3531cb0ef41Sopenharmony_ci            if (j === len) {
3541cb0ef41Sopenharmony_ci              // We matched a UNC root only
3551cb0ef41Sopenharmony_ci              // Return the normalized version of the UNC root since there
3561cb0ef41Sopenharmony_ci              // is nothing left to process
3571cb0ef41Sopenharmony_ci              return `\\\\${firstPart}\\${StringPrototypeSlice(path, last)}\\`;
3581cb0ef41Sopenharmony_ci            }
3591cb0ef41Sopenharmony_ci            if (j !== last) {
3601cb0ef41Sopenharmony_ci              // We matched a UNC root with leftovers
3611cb0ef41Sopenharmony_ci              device =
3621cb0ef41Sopenharmony_ci                `\\\\${firstPart}\\${StringPrototypeSlice(path, last, j)}`;
3631cb0ef41Sopenharmony_ci              rootEnd = j;
3641cb0ef41Sopenharmony_ci            }
3651cb0ef41Sopenharmony_ci          }
3661cb0ef41Sopenharmony_ci        }
3671cb0ef41Sopenharmony_ci      } else {
3681cb0ef41Sopenharmony_ci        rootEnd = 1;
3691cb0ef41Sopenharmony_ci      }
3701cb0ef41Sopenharmony_ci    } else if (isWindowsDeviceRoot(code) &&
3711cb0ef41Sopenharmony_ci               StringPrototypeCharCodeAt(path, 1) === CHAR_COLON) {
3721cb0ef41Sopenharmony_ci      // Possible device root
3731cb0ef41Sopenharmony_ci      device = StringPrototypeSlice(path, 0, 2);
3741cb0ef41Sopenharmony_ci      rootEnd = 2;
3751cb0ef41Sopenharmony_ci      if (len > 2 && isPathSeparator(StringPrototypeCharCodeAt(path, 2))) {
3761cb0ef41Sopenharmony_ci        // Treat separator following drive name as an absolute path
3771cb0ef41Sopenharmony_ci        // indicator
3781cb0ef41Sopenharmony_ci        isAbsolute = true;
3791cb0ef41Sopenharmony_ci        rootEnd = 3;
3801cb0ef41Sopenharmony_ci      }
3811cb0ef41Sopenharmony_ci    }
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_ci    let tail = rootEnd < len ?
3841cb0ef41Sopenharmony_ci      normalizeString(StringPrototypeSlice(path, rootEnd),
3851cb0ef41Sopenharmony_ci                      !isAbsolute, '\\', isPathSeparator) :
3861cb0ef41Sopenharmony_ci      '';
3871cb0ef41Sopenharmony_ci    if (tail.length === 0 && !isAbsolute)
3881cb0ef41Sopenharmony_ci      tail = '.';
3891cb0ef41Sopenharmony_ci    if (tail.length > 0 &&
3901cb0ef41Sopenharmony_ci        isPathSeparator(StringPrototypeCharCodeAt(path, len - 1)))
3911cb0ef41Sopenharmony_ci      tail += '\\';
3921cb0ef41Sopenharmony_ci    if (device === undefined) {
3931cb0ef41Sopenharmony_ci      return isAbsolute ? `\\${tail}` : tail;
3941cb0ef41Sopenharmony_ci    }
3951cb0ef41Sopenharmony_ci    return isAbsolute ? `${device}\\${tail}` : `${device}${tail}`;
3961cb0ef41Sopenharmony_ci  },
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_ci  /**
3991cb0ef41Sopenharmony_ci   * @param {string} path
4001cb0ef41Sopenharmony_ci   * @returns {boolean}
4011cb0ef41Sopenharmony_ci   */
4021cb0ef41Sopenharmony_ci  isAbsolute(path) {
4031cb0ef41Sopenharmony_ci    validateString(path, 'path');
4041cb0ef41Sopenharmony_ci    const len = path.length;
4051cb0ef41Sopenharmony_ci    if (len === 0)
4061cb0ef41Sopenharmony_ci      return false;
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ci    const code = StringPrototypeCharCodeAt(path, 0);
4091cb0ef41Sopenharmony_ci    return isPathSeparator(code) ||
4101cb0ef41Sopenharmony_ci      // Possible device root
4111cb0ef41Sopenharmony_ci      (len > 2 &&
4121cb0ef41Sopenharmony_ci      isWindowsDeviceRoot(code) &&
4131cb0ef41Sopenharmony_ci      StringPrototypeCharCodeAt(path, 1) === CHAR_COLON &&
4141cb0ef41Sopenharmony_ci      isPathSeparator(StringPrototypeCharCodeAt(path, 2)));
4151cb0ef41Sopenharmony_ci  },
4161cb0ef41Sopenharmony_ci
4171cb0ef41Sopenharmony_ci  /**
4181cb0ef41Sopenharmony_ci   * @param {...string} args
4191cb0ef41Sopenharmony_ci   * @returns {string}
4201cb0ef41Sopenharmony_ci   */
4211cb0ef41Sopenharmony_ci  join(...args) {
4221cb0ef41Sopenharmony_ci    if (args.length === 0)
4231cb0ef41Sopenharmony_ci      return '.';
4241cb0ef41Sopenharmony_ci
4251cb0ef41Sopenharmony_ci    let joined;
4261cb0ef41Sopenharmony_ci    let firstPart;
4271cb0ef41Sopenharmony_ci    for (let i = 0; i < args.length; ++i) {
4281cb0ef41Sopenharmony_ci      const arg = args[i];
4291cb0ef41Sopenharmony_ci      validateString(arg, 'path');
4301cb0ef41Sopenharmony_ci      if (arg.length > 0) {
4311cb0ef41Sopenharmony_ci        if (joined === undefined)
4321cb0ef41Sopenharmony_ci          joined = firstPart = arg;
4331cb0ef41Sopenharmony_ci        else
4341cb0ef41Sopenharmony_ci          joined += `\\${arg}`;
4351cb0ef41Sopenharmony_ci      }
4361cb0ef41Sopenharmony_ci    }
4371cb0ef41Sopenharmony_ci
4381cb0ef41Sopenharmony_ci    if (joined === undefined)
4391cb0ef41Sopenharmony_ci      return '.';
4401cb0ef41Sopenharmony_ci
4411cb0ef41Sopenharmony_ci    // Make sure that the joined path doesn't start with two slashes, because
4421cb0ef41Sopenharmony_ci    // normalize() will mistake it for a UNC path then.
4431cb0ef41Sopenharmony_ci    //
4441cb0ef41Sopenharmony_ci    // This step is skipped when it is very clear that the user actually
4451cb0ef41Sopenharmony_ci    // intended to point at a UNC path. This is assumed when the first
4461cb0ef41Sopenharmony_ci    // non-empty string arguments starts with exactly two slashes followed by
4471cb0ef41Sopenharmony_ci    // at least one more non-slash character.
4481cb0ef41Sopenharmony_ci    //
4491cb0ef41Sopenharmony_ci    // Note that for normalize() to treat a path as a UNC path it needs to
4501cb0ef41Sopenharmony_ci    // have at least 2 components, so we don't filter for that here.
4511cb0ef41Sopenharmony_ci    // This means that the user can use join to construct UNC paths from
4521cb0ef41Sopenharmony_ci    // a server name and a share name; for example:
4531cb0ef41Sopenharmony_ci    //   path.join('//server', 'share') -> '\\\\server\\share\\')
4541cb0ef41Sopenharmony_ci    let needsReplace = true;
4551cb0ef41Sopenharmony_ci    let slashCount = 0;
4561cb0ef41Sopenharmony_ci    if (isPathSeparator(StringPrototypeCharCodeAt(firstPart, 0))) {
4571cb0ef41Sopenharmony_ci      ++slashCount;
4581cb0ef41Sopenharmony_ci      const firstLen = firstPart.length;
4591cb0ef41Sopenharmony_ci      if (firstLen > 1 &&
4601cb0ef41Sopenharmony_ci          isPathSeparator(StringPrototypeCharCodeAt(firstPart, 1))) {
4611cb0ef41Sopenharmony_ci        ++slashCount;
4621cb0ef41Sopenharmony_ci        if (firstLen > 2) {
4631cb0ef41Sopenharmony_ci          if (isPathSeparator(StringPrototypeCharCodeAt(firstPart, 2)))
4641cb0ef41Sopenharmony_ci            ++slashCount;
4651cb0ef41Sopenharmony_ci          else {
4661cb0ef41Sopenharmony_ci            // We matched a UNC path in the first part
4671cb0ef41Sopenharmony_ci            needsReplace = false;
4681cb0ef41Sopenharmony_ci          }
4691cb0ef41Sopenharmony_ci        }
4701cb0ef41Sopenharmony_ci      }
4711cb0ef41Sopenharmony_ci    }
4721cb0ef41Sopenharmony_ci    if (needsReplace) {
4731cb0ef41Sopenharmony_ci      // Find any more consecutive slashes we need to replace
4741cb0ef41Sopenharmony_ci      while (slashCount < joined.length &&
4751cb0ef41Sopenharmony_ci             isPathSeparator(StringPrototypeCharCodeAt(joined, slashCount))) {
4761cb0ef41Sopenharmony_ci        slashCount++;
4771cb0ef41Sopenharmony_ci      }
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ci      // Replace the slashes if needed
4801cb0ef41Sopenharmony_ci      if (slashCount >= 2)
4811cb0ef41Sopenharmony_ci        joined = `\\${StringPrototypeSlice(joined, slashCount)}`;
4821cb0ef41Sopenharmony_ci    }
4831cb0ef41Sopenharmony_ci
4841cb0ef41Sopenharmony_ci    return win32.normalize(joined);
4851cb0ef41Sopenharmony_ci  },
4861cb0ef41Sopenharmony_ci
4871cb0ef41Sopenharmony_ci  /**
4881cb0ef41Sopenharmony_ci   * It will solve the relative path from `from` to `to`, for instance
4891cb0ef41Sopenharmony_ci   * from = 'C:\\orandea\\test\\aaa'
4901cb0ef41Sopenharmony_ci   * to = 'C:\\orandea\\impl\\bbb'
4911cb0ef41Sopenharmony_ci   * The output of the function should be: '..\\..\\impl\\bbb'
4921cb0ef41Sopenharmony_ci   * @param {string} from
4931cb0ef41Sopenharmony_ci   * @param {string} to
4941cb0ef41Sopenharmony_ci   * @returns {string}
4951cb0ef41Sopenharmony_ci   */
4961cb0ef41Sopenharmony_ci  relative(from, to) {
4971cb0ef41Sopenharmony_ci    validateString(from, 'from');
4981cb0ef41Sopenharmony_ci    validateString(to, 'to');
4991cb0ef41Sopenharmony_ci
5001cb0ef41Sopenharmony_ci    if (from === to)
5011cb0ef41Sopenharmony_ci      return '';
5021cb0ef41Sopenharmony_ci
5031cb0ef41Sopenharmony_ci    const fromOrig = win32.resolve(from);
5041cb0ef41Sopenharmony_ci    const toOrig = win32.resolve(to);
5051cb0ef41Sopenharmony_ci
5061cb0ef41Sopenharmony_ci    if (fromOrig === toOrig)
5071cb0ef41Sopenharmony_ci      return '';
5081cb0ef41Sopenharmony_ci
5091cb0ef41Sopenharmony_ci    from = StringPrototypeToLowerCase(fromOrig);
5101cb0ef41Sopenharmony_ci    to = StringPrototypeToLowerCase(toOrig);
5111cb0ef41Sopenharmony_ci
5121cb0ef41Sopenharmony_ci    if (from === to)
5131cb0ef41Sopenharmony_ci      return '';
5141cb0ef41Sopenharmony_ci
5151cb0ef41Sopenharmony_ci    // Trim any leading backslashes
5161cb0ef41Sopenharmony_ci    let fromStart = 0;
5171cb0ef41Sopenharmony_ci    while (fromStart < from.length &&
5181cb0ef41Sopenharmony_ci           StringPrototypeCharCodeAt(from, fromStart) === CHAR_BACKWARD_SLASH) {
5191cb0ef41Sopenharmony_ci      fromStart++;
5201cb0ef41Sopenharmony_ci    }
5211cb0ef41Sopenharmony_ci    // Trim trailing backslashes (applicable to UNC paths only)
5221cb0ef41Sopenharmony_ci    let fromEnd = from.length;
5231cb0ef41Sopenharmony_ci    while (
5241cb0ef41Sopenharmony_ci      fromEnd - 1 > fromStart &&
5251cb0ef41Sopenharmony_ci      StringPrototypeCharCodeAt(from, fromEnd - 1) === CHAR_BACKWARD_SLASH
5261cb0ef41Sopenharmony_ci    ) {
5271cb0ef41Sopenharmony_ci      fromEnd--;
5281cb0ef41Sopenharmony_ci    }
5291cb0ef41Sopenharmony_ci    const fromLen = fromEnd - fromStart;
5301cb0ef41Sopenharmony_ci
5311cb0ef41Sopenharmony_ci    // Trim any leading backslashes
5321cb0ef41Sopenharmony_ci    let toStart = 0;
5331cb0ef41Sopenharmony_ci    while (toStart < to.length &&
5341cb0ef41Sopenharmony_ci           StringPrototypeCharCodeAt(to, toStart) === CHAR_BACKWARD_SLASH) {
5351cb0ef41Sopenharmony_ci      toStart++;
5361cb0ef41Sopenharmony_ci    }
5371cb0ef41Sopenharmony_ci    // Trim trailing backslashes (applicable to UNC paths only)
5381cb0ef41Sopenharmony_ci    let toEnd = to.length;
5391cb0ef41Sopenharmony_ci    while (toEnd - 1 > toStart &&
5401cb0ef41Sopenharmony_ci           StringPrototypeCharCodeAt(to, toEnd - 1) === CHAR_BACKWARD_SLASH) {
5411cb0ef41Sopenharmony_ci      toEnd--;
5421cb0ef41Sopenharmony_ci    }
5431cb0ef41Sopenharmony_ci    const toLen = toEnd - toStart;
5441cb0ef41Sopenharmony_ci
5451cb0ef41Sopenharmony_ci    // Compare paths to find the longest common path from root
5461cb0ef41Sopenharmony_ci    const length = fromLen < toLen ? fromLen : toLen;
5471cb0ef41Sopenharmony_ci    let lastCommonSep = -1;
5481cb0ef41Sopenharmony_ci    let i = 0;
5491cb0ef41Sopenharmony_ci    for (; i < length; i++) {
5501cb0ef41Sopenharmony_ci      const fromCode = StringPrototypeCharCodeAt(from, fromStart + i);
5511cb0ef41Sopenharmony_ci      if (fromCode !== StringPrototypeCharCodeAt(to, toStart + i))
5521cb0ef41Sopenharmony_ci        break;
5531cb0ef41Sopenharmony_ci      else if (fromCode === CHAR_BACKWARD_SLASH)
5541cb0ef41Sopenharmony_ci        lastCommonSep = i;
5551cb0ef41Sopenharmony_ci    }
5561cb0ef41Sopenharmony_ci
5571cb0ef41Sopenharmony_ci    // We found a mismatch before the first common path separator was seen, so
5581cb0ef41Sopenharmony_ci    // return the original `to`.
5591cb0ef41Sopenharmony_ci    if (i !== length) {
5601cb0ef41Sopenharmony_ci      if (lastCommonSep === -1)
5611cb0ef41Sopenharmony_ci        return toOrig;
5621cb0ef41Sopenharmony_ci    } else {
5631cb0ef41Sopenharmony_ci      if (toLen > length) {
5641cb0ef41Sopenharmony_ci        if (StringPrototypeCharCodeAt(to, toStart + i) ===
5651cb0ef41Sopenharmony_ci            CHAR_BACKWARD_SLASH) {
5661cb0ef41Sopenharmony_ci          // We get here if `from` is the exact base path for `to`.
5671cb0ef41Sopenharmony_ci          // For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz'
5681cb0ef41Sopenharmony_ci          return StringPrototypeSlice(toOrig, toStart + i + 1);
5691cb0ef41Sopenharmony_ci        }
5701cb0ef41Sopenharmony_ci        if (i === 2) {
5711cb0ef41Sopenharmony_ci          // We get here if `from` is the device root.
5721cb0ef41Sopenharmony_ci          // For example: from='C:\\'; to='C:\\foo'
5731cb0ef41Sopenharmony_ci          return StringPrototypeSlice(toOrig, toStart + i);
5741cb0ef41Sopenharmony_ci        }
5751cb0ef41Sopenharmony_ci      }
5761cb0ef41Sopenharmony_ci      if (fromLen > length) {
5771cb0ef41Sopenharmony_ci        if (StringPrototypeCharCodeAt(from, fromStart + i) ===
5781cb0ef41Sopenharmony_ci            CHAR_BACKWARD_SLASH) {
5791cb0ef41Sopenharmony_ci          // We get here if `to` is the exact base path for `from`.
5801cb0ef41Sopenharmony_ci          // For example: from='C:\\foo\\bar'; to='C:\\foo'
5811cb0ef41Sopenharmony_ci          lastCommonSep = i;
5821cb0ef41Sopenharmony_ci        } else if (i === 2) {
5831cb0ef41Sopenharmony_ci          // We get here if `to` is the device root.
5841cb0ef41Sopenharmony_ci          // For example: from='C:\\foo\\bar'; to='C:\\'
5851cb0ef41Sopenharmony_ci          lastCommonSep = 3;
5861cb0ef41Sopenharmony_ci        }
5871cb0ef41Sopenharmony_ci      }
5881cb0ef41Sopenharmony_ci      if (lastCommonSep === -1)
5891cb0ef41Sopenharmony_ci        lastCommonSep = 0;
5901cb0ef41Sopenharmony_ci    }
5911cb0ef41Sopenharmony_ci
5921cb0ef41Sopenharmony_ci    let out = '';
5931cb0ef41Sopenharmony_ci    // Generate the relative path based on the path difference between `to` and
5941cb0ef41Sopenharmony_ci    // `from`
5951cb0ef41Sopenharmony_ci    for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
5961cb0ef41Sopenharmony_ci      if (i === fromEnd ||
5971cb0ef41Sopenharmony_ci          StringPrototypeCharCodeAt(from, i) === CHAR_BACKWARD_SLASH) {
5981cb0ef41Sopenharmony_ci        out += out.length === 0 ? '..' : '\\..';
5991cb0ef41Sopenharmony_ci      }
6001cb0ef41Sopenharmony_ci    }
6011cb0ef41Sopenharmony_ci
6021cb0ef41Sopenharmony_ci    toStart += lastCommonSep;
6031cb0ef41Sopenharmony_ci
6041cb0ef41Sopenharmony_ci    // Lastly, append the rest of the destination (`to`) path that comes after
6051cb0ef41Sopenharmony_ci    // the common path parts
6061cb0ef41Sopenharmony_ci    if (out.length > 0)
6071cb0ef41Sopenharmony_ci      return `${out}${StringPrototypeSlice(toOrig, toStart, toEnd)}`;
6081cb0ef41Sopenharmony_ci
6091cb0ef41Sopenharmony_ci    if (StringPrototypeCharCodeAt(toOrig, toStart) === CHAR_BACKWARD_SLASH)
6101cb0ef41Sopenharmony_ci      ++toStart;
6111cb0ef41Sopenharmony_ci    return StringPrototypeSlice(toOrig, toStart, toEnd);
6121cb0ef41Sopenharmony_ci  },
6131cb0ef41Sopenharmony_ci
6141cb0ef41Sopenharmony_ci  /**
6151cb0ef41Sopenharmony_ci   * @param {string} path
6161cb0ef41Sopenharmony_ci   * @returns {string}
6171cb0ef41Sopenharmony_ci   */
6181cb0ef41Sopenharmony_ci  toNamespacedPath(path) {
6191cb0ef41Sopenharmony_ci    // Note: this will *probably* throw somewhere.
6201cb0ef41Sopenharmony_ci    if (typeof path !== 'string' || path.length === 0)
6211cb0ef41Sopenharmony_ci      return path;
6221cb0ef41Sopenharmony_ci
6231cb0ef41Sopenharmony_ci    const resolvedPath = win32.resolve(path);
6241cb0ef41Sopenharmony_ci
6251cb0ef41Sopenharmony_ci    if (resolvedPath.length <= 2)
6261cb0ef41Sopenharmony_ci      return path;
6271cb0ef41Sopenharmony_ci
6281cb0ef41Sopenharmony_ci    if (StringPrototypeCharCodeAt(resolvedPath, 0) === CHAR_BACKWARD_SLASH) {
6291cb0ef41Sopenharmony_ci      // Possible UNC root
6301cb0ef41Sopenharmony_ci      if (StringPrototypeCharCodeAt(resolvedPath, 1) === CHAR_BACKWARD_SLASH) {
6311cb0ef41Sopenharmony_ci        const code = StringPrototypeCharCodeAt(resolvedPath, 2);
6321cb0ef41Sopenharmony_ci        if (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) {
6331cb0ef41Sopenharmony_ci          // Matched non-long UNC root, convert the path to a long UNC path
6341cb0ef41Sopenharmony_ci          return `\\\\?\\UNC\\${StringPrototypeSlice(resolvedPath, 2)}`;
6351cb0ef41Sopenharmony_ci        }
6361cb0ef41Sopenharmony_ci      }
6371cb0ef41Sopenharmony_ci    } else if (
6381cb0ef41Sopenharmony_ci      isWindowsDeviceRoot(StringPrototypeCharCodeAt(resolvedPath, 0)) &&
6391cb0ef41Sopenharmony_ci      StringPrototypeCharCodeAt(resolvedPath, 1) === CHAR_COLON &&
6401cb0ef41Sopenharmony_ci      StringPrototypeCharCodeAt(resolvedPath, 2) === CHAR_BACKWARD_SLASH
6411cb0ef41Sopenharmony_ci    ) {
6421cb0ef41Sopenharmony_ci      // Matched device root, convert the path to a long UNC path
6431cb0ef41Sopenharmony_ci      return `\\\\?\\${resolvedPath}`;
6441cb0ef41Sopenharmony_ci    }
6451cb0ef41Sopenharmony_ci
6461cb0ef41Sopenharmony_ci    return path;
6471cb0ef41Sopenharmony_ci  },
6481cb0ef41Sopenharmony_ci
6491cb0ef41Sopenharmony_ci  /**
6501cb0ef41Sopenharmony_ci   * @param {string} path
6511cb0ef41Sopenharmony_ci   * @returns {string}
6521cb0ef41Sopenharmony_ci   */
6531cb0ef41Sopenharmony_ci  dirname(path) {
6541cb0ef41Sopenharmony_ci    validateString(path, 'path');
6551cb0ef41Sopenharmony_ci    const len = path.length;
6561cb0ef41Sopenharmony_ci    if (len === 0)
6571cb0ef41Sopenharmony_ci      return '.';
6581cb0ef41Sopenharmony_ci    let rootEnd = -1;
6591cb0ef41Sopenharmony_ci    let offset = 0;
6601cb0ef41Sopenharmony_ci    const code = StringPrototypeCharCodeAt(path, 0);
6611cb0ef41Sopenharmony_ci
6621cb0ef41Sopenharmony_ci    if (len === 1) {
6631cb0ef41Sopenharmony_ci      // `path` contains just a path separator, exit early to avoid
6641cb0ef41Sopenharmony_ci      // unnecessary work or a dot.
6651cb0ef41Sopenharmony_ci      return isPathSeparator(code) ? path : '.';
6661cb0ef41Sopenharmony_ci    }
6671cb0ef41Sopenharmony_ci
6681cb0ef41Sopenharmony_ci    // Try to match a root
6691cb0ef41Sopenharmony_ci    if (isPathSeparator(code)) {
6701cb0ef41Sopenharmony_ci      // Possible UNC root
6711cb0ef41Sopenharmony_ci
6721cb0ef41Sopenharmony_ci      rootEnd = offset = 1;
6731cb0ef41Sopenharmony_ci
6741cb0ef41Sopenharmony_ci      if (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) {
6751cb0ef41Sopenharmony_ci        // Matched double path separator at beginning
6761cb0ef41Sopenharmony_ci        let j = 2;
6771cb0ef41Sopenharmony_ci        let last = j;
6781cb0ef41Sopenharmony_ci        // Match 1 or more non-path separators
6791cb0ef41Sopenharmony_ci        while (j < len &&
6801cb0ef41Sopenharmony_ci               !isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
6811cb0ef41Sopenharmony_ci          j++;
6821cb0ef41Sopenharmony_ci        }
6831cb0ef41Sopenharmony_ci        if (j < len && j !== last) {
6841cb0ef41Sopenharmony_ci          // Matched!
6851cb0ef41Sopenharmony_ci          last = j;
6861cb0ef41Sopenharmony_ci          // Match 1 or more path separators
6871cb0ef41Sopenharmony_ci          while (j < len &&
6881cb0ef41Sopenharmony_ci                 isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
6891cb0ef41Sopenharmony_ci            j++;
6901cb0ef41Sopenharmony_ci          }
6911cb0ef41Sopenharmony_ci          if (j < len && j !== last) {
6921cb0ef41Sopenharmony_ci            // Matched!
6931cb0ef41Sopenharmony_ci            last = j;
6941cb0ef41Sopenharmony_ci            // Match 1 or more non-path separators
6951cb0ef41Sopenharmony_ci            while (j < len &&
6961cb0ef41Sopenharmony_ci                   !isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
6971cb0ef41Sopenharmony_ci              j++;
6981cb0ef41Sopenharmony_ci            }
6991cb0ef41Sopenharmony_ci            if (j === len) {
7001cb0ef41Sopenharmony_ci              // We matched a UNC root only
7011cb0ef41Sopenharmony_ci              return path;
7021cb0ef41Sopenharmony_ci            }
7031cb0ef41Sopenharmony_ci            if (j !== last) {
7041cb0ef41Sopenharmony_ci              // We matched a UNC root with leftovers
7051cb0ef41Sopenharmony_ci
7061cb0ef41Sopenharmony_ci              // Offset by 1 to include the separator after the UNC root to
7071cb0ef41Sopenharmony_ci              // treat it as a "normal root" on top of a (UNC) root
7081cb0ef41Sopenharmony_ci              rootEnd = offset = j + 1;
7091cb0ef41Sopenharmony_ci            }
7101cb0ef41Sopenharmony_ci          }
7111cb0ef41Sopenharmony_ci        }
7121cb0ef41Sopenharmony_ci      }
7131cb0ef41Sopenharmony_ci    // Possible device root
7141cb0ef41Sopenharmony_ci    } else if (isWindowsDeviceRoot(code) &&
7151cb0ef41Sopenharmony_ci               StringPrototypeCharCodeAt(path, 1) === CHAR_COLON) {
7161cb0ef41Sopenharmony_ci      rootEnd =
7171cb0ef41Sopenharmony_ci        len > 2 && isPathSeparator(StringPrototypeCharCodeAt(path, 2)) ? 3 : 2;
7181cb0ef41Sopenharmony_ci      offset = rootEnd;
7191cb0ef41Sopenharmony_ci    }
7201cb0ef41Sopenharmony_ci
7211cb0ef41Sopenharmony_ci    let end = -1;
7221cb0ef41Sopenharmony_ci    let matchedSlash = true;
7231cb0ef41Sopenharmony_ci    for (let i = len - 1; i >= offset; --i) {
7241cb0ef41Sopenharmony_ci      if (isPathSeparator(StringPrototypeCharCodeAt(path, i))) {
7251cb0ef41Sopenharmony_ci        if (!matchedSlash) {
7261cb0ef41Sopenharmony_ci          end = i;
7271cb0ef41Sopenharmony_ci          break;
7281cb0ef41Sopenharmony_ci        }
7291cb0ef41Sopenharmony_ci      } else {
7301cb0ef41Sopenharmony_ci        // We saw the first non-path separator
7311cb0ef41Sopenharmony_ci        matchedSlash = false;
7321cb0ef41Sopenharmony_ci      }
7331cb0ef41Sopenharmony_ci    }
7341cb0ef41Sopenharmony_ci
7351cb0ef41Sopenharmony_ci    if (end === -1) {
7361cb0ef41Sopenharmony_ci      if (rootEnd === -1)
7371cb0ef41Sopenharmony_ci        return '.';
7381cb0ef41Sopenharmony_ci
7391cb0ef41Sopenharmony_ci      end = rootEnd;
7401cb0ef41Sopenharmony_ci    }
7411cb0ef41Sopenharmony_ci    return StringPrototypeSlice(path, 0, end);
7421cb0ef41Sopenharmony_ci  },
7431cb0ef41Sopenharmony_ci
7441cb0ef41Sopenharmony_ci  /**
7451cb0ef41Sopenharmony_ci   * @param {string} path
7461cb0ef41Sopenharmony_ci   * @param {string} [suffix]
7471cb0ef41Sopenharmony_ci   * @returns {string}
7481cb0ef41Sopenharmony_ci   */
7491cb0ef41Sopenharmony_ci  basename(path, suffix) {
7501cb0ef41Sopenharmony_ci    if (suffix !== undefined)
7511cb0ef41Sopenharmony_ci      validateString(suffix, 'ext');
7521cb0ef41Sopenharmony_ci    validateString(path, 'path');
7531cb0ef41Sopenharmony_ci    let start = 0;
7541cb0ef41Sopenharmony_ci    let end = -1;
7551cb0ef41Sopenharmony_ci    let matchedSlash = true;
7561cb0ef41Sopenharmony_ci
7571cb0ef41Sopenharmony_ci    // Check for a drive letter prefix so as not to mistake the following
7581cb0ef41Sopenharmony_ci    // path separator as an extra separator at the end of the path that can be
7591cb0ef41Sopenharmony_ci    // disregarded
7601cb0ef41Sopenharmony_ci    if (path.length >= 2 &&
7611cb0ef41Sopenharmony_ci        isWindowsDeviceRoot(StringPrototypeCharCodeAt(path, 0)) &&
7621cb0ef41Sopenharmony_ci        StringPrototypeCharCodeAt(path, 1) === CHAR_COLON) {
7631cb0ef41Sopenharmony_ci      start = 2;
7641cb0ef41Sopenharmony_ci    }
7651cb0ef41Sopenharmony_ci
7661cb0ef41Sopenharmony_ci    if (suffix !== undefined && suffix.length > 0 && suffix.length <= path.length) {
7671cb0ef41Sopenharmony_ci      if (suffix === path)
7681cb0ef41Sopenharmony_ci        return '';
7691cb0ef41Sopenharmony_ci      let extIdx = suffix.length - 1;
7701cb0ef41Sopenharmony_ci      let firstNonSlashEnd = -1;
7711cb0ef41Sopenharmony_ci      for (let i = path.length - 1; i >= start; --i) {
7721cb0ef41Sopenharmony_ci        const code = StringPrototypeCharCodeAt(path, i);
7731cb0ef41Sopenharmony_ci        if (isPathSeparator(code)) {
7741cb0ef41Sopenharmony_ci          // If we reached a path separator that was not part of a set of path
7751cb0ef41Sopenharmony_ci          // separators at the end of the string, stop now
7761cb0ef41Sopenharmony_ci          if (!matchedSlash) {
7771cb0ef41Sopenharmony_ci            start = i + 1;
7781cb0ef41Sopenharmony_ci            break;
7791cb0ef41Sopenharmony_ci          }
7801cb0ef41Sopenharmony_ci        } else {
7811cb0ef41Sopenharmony_ci          if (firstNonSlashEnd === -1) {
7821cb0ef41Sopenharmony_ci            // We saw the first non-path separator, remember this index in case
7831cb0ef41Sopenharmony_ci            // we need it if the extension ends up not matching
7841cb0ef41Sopenharmony_ci            matchedSlash = false;
7851cb0ef41Sopenharmony_ci            firstNonSlashEnd = i + 1;
7861cb0ef41Sopenharmony_ci          }
7871cb0ef41Sopenharmony_ci          if (extIdx >= 0) {
7881cb0ef41Sopenharmony_ci            // Try to match the explicit extension
7891cb0ef41Sopenharmony_ci            if (code === StringPrototypeCharCodeAt(suffix, extIdx)) {
7901cb0ef41Sopenharmony_ci              if (--extIdx === -1) {
7911cb0ef41Sopenharmony_ci                // We matched the extension, so mark this as the end of our path
7921cb0ef41Sopenharmony_ci                // component
7931cb0ef41Sopenharmony_ci                end = i;
7941cb0ef41Sopenharmony_ci              }
7951cb0ef41Sopenharmony_ci            } else {
7961cb0ef41Sopenharmony_ci              // Extension does not match, so our result is the entire path
7971cb0ef41Sopenharmony_ci              // component
7981cb0ef41Sopenharmony_ci              extIdx = -1;
7991cb0ef41Sopenharmony_ci              end = firstNonSlashEnd;
8001cb0ef41Sopenharmony_ci            }
8011cb0ef41Sopenharmony_ci          }
8021cb0ef41Sopenharmony_ci        }
8031cb0ef41Sopenharmony_ci      }
8041cb0ef41Sopenharmony_ci
8051cb0ef41Sopenharmony_ci      if (start === end)
8061cb0ef41Sopenharmony_ci        end = firstNonSlashEnd;
8071cb0ef41Sopenharmony_ci      else if (end === -1)
8081cb0ef41Sopenharmony_ci        end = path.length;
8091cb0ef41Sopenharmony_ci      return StringPrototypeSlice(path, start, end);
8101cb0ef41Sopenharmony_ci    }
8111cb0ef41Sopenharmony_ci    for (let i = path.length - 1; i >= start; --i) {
8121cb0ef41Sopenharmony_ci      if (isPathSeparator(StringPrototypeCharCodeAt(path, i))) {
8131cb0ef41Sopenharmony_ci        // If we reached a path separator that was not part of a set of path
8141cb0ef41Sopenharmony_ci        // separators at the end of the string, stop now
8151cb0ef41Sopenharmony_ci        if (!matchedSlash) {
8161cb0ef41Sopenharmony_ci          start = i + 1;
8171cb0ef41Sopenharmony_ci          break;
8181cb0ef41Sopenharmony_ci        }
8191cb0ef41Sopenharmony_ci      } else if (end === -1) {
8201cb0ef41Sopenharmony_ci        // We saw the first non-path separator, mark this as the end of our
8211cb0ef41Sopenharmony_ci        // path component
8221cb0ef41Sopenharmony_ci        matchedSlash = false;
8231cb0ef41Sopenharmony_ci        end = i + 1;
8241cb0ef41Sopenharmony_ci      }
8251cb0ef41Sopenharmony_ci    }
8261cb0ef41Sopenharmony_ci
8271cb0ef41Sopenharmony_ci    if (end === -1)
8281cb0ef41Sopenharmony_ci      return '';
8291cb0ef41Sopenharmony_ci    return StringPrototypeSlice(path, start, end);
8301cb0ef41Sopenharmony_ci  },
8311cb0ef41Sopenharmony_ci
8321cb0ef41Sopenharmony_ci  /**
8331cb0ef41Sopenharmony_ci   * @param {string} path
8341cb0ef41Sopenharmony_ci   * @returns {string}
8351cb0ef41Sopenharmony_ci   */
8361cb0ef41Sopenharmony_ci  extname(path) {
8371cb0ef41Sopenharmony_ci    validateString(path, 'path');
8381cb0ef41Sopenharmony_ci    let start = 0;
8391cb0ef41Sopenharmony_ci    let startDot = -1;
8401cb0ef41Sopenharmony_ci    let startPart = 0;
8411cb0ef41Sopenharmony_ci    let end = -1;
8421cb0ef41Sopenharmony_ci    let matchedSlash = true;
8431cb0ef41Sopenharmony_ci    // Track the state of characters (if any) we see before our first dot and
8441cb0ef41Sopenharmony_ci    // after any path separator we find
8451cb0ef41Sopenharmony_ci    let preDotState = 0;
8461cb0ef41Sopenharmony_ci
8471cb0ef41Sopenharmony_ci    // Check for a drive letter prefix so as not to mistake the following
8481cb0ef41Sopenharmony_ci    // path separator as an extra separator at the end of the path that can be
8491cb0ef41Sopenharmony_ci    // disregarded
8501cb0ef41Sopenharmony_ci
8511cb0ef41Sopenharmony_ci    if (path.length >= 2 &&
8521cb0ef41Sopenharmony_ci        StringPrototypeCharCodeAt(path, 1) === CHAR_COLON &&
8531cb0ef41Sopenharmony_ci        isWindowsDeviceRoot(StringPrototypeCharCodeAt(path, 0))) {
8541cb0ef41Sopenharmony_ci      start = startPart = 2;
8551cb0ef41Sopenharmony_ci    }
8561cb0ef41Sopenharmony_ci
8571cb0ef41Sopenharmony_ci    for (let i = path.length - 1; i >= start; --i) {
8581cb0ef41Sopenharmony_ci      const code = StringPrototypeCharCodeAt(path, i);
8591cb0ef41Sopenharmony_ci      if (isPathSeparator(code)) {
8601cb0ef41Sopenharmony_ci        // If we reached a path separator that was not part of a set of path
8611cb0ef41Sopenharmony_ci        // separators at the end of the string, stop now
8621cb0ef41Sopenharmony_ci        if (!matchedSlash) {
8631cb0ef41Sopenharmony_ci          startPart = i + 1;
8641cb0ef41Sopenharmony_ci          break;
8651cb0ef41Sopenharmony_ci        }
8661cb0ef41Sopenharmony_ci        continue;
8671cb0ef41Sopenharmony_ci      }
8681cb0ef41Sopenharmony_ci      if (end === -1) {
8691cb0ef41Sopenharmony_ci        // We saw the first non-path separator, mark this as the end of our
8701cb0ef41Sopenharmony_ci        // extension
8711cb0ef41Sopenharmony_ci        matchedSlash = false;
8721cb0ef41Sopenharmony_ci        end = i + 1;
8731cb0ef41Sopenharmony_ci      }
8741cb0ef41Sopenharmony_ci      if (code === CHAR_DOT) {
8751cb0ef41Sopenharmony_ci        // If this is our first dot, mark it as the start of our extension
8761cb0ef41Sopenharmony_ci        if (startDot === -1)
8771cb0ef41Sopenharmony_ci          startDot = i;
8781cb0ef41Sopenharmony_ci        else if (preDotState !== 1)
8791cb0ef41Sopenharmony_ci          preDotState = 1;
8801cb0ef41Sopenharmony_ci      } else if (startDot !== -1) {
8811cb0ef41Sopenharmony_ci        // We saw a non-dot and non-path separator before our dot, so we should
8821cb0ef41Sopenharmony_ci        // have a good chance at having a non-empty extension
8831cb0ef41Sopenharmony_ci        preDotState = -1;
8841cb0ef41Sopenharmony_ci      }
8851cb0ef41Sopenharmony_ci    }
8861cb0ef41Sopenharmony_ci
8871cb0ef41Sopenharmony_ci    if (startDot === -1 ||
8881cb0ef41Sopenharmony_ci        end === -1 ||
8891cb0ef41Sopenharmony_ci        // We saw a non-dot character immediately before the dot
8901cb0ef41Sopenharmony_ci        preDotState === 0 ||
8911cb0ef41Sopenharmony_ci        // The (right-most) trimmed path component is exactly '..'
8921cb0ef41Sopenharmony_ci        (preDotState === 1 &&
8931cb0ef41Sopenharmony_ci         startDot === end - 1 &&
8941cb0ef41Sopenharmony_ci         startDot === startPart + 1)) {
8951cb0ef41Sopenharmony_ci      return '';
8961cb0ef41Sopenharmony_ci    }
8971cb0ef41Sopenharmony_ci    return StringPrototypeSlice(path, startDot, end);
8981cb0ef41Sopenharmony_ci  },
8991cb0ef41Sopenharmony_ci
9001cb0ef41Sopenharmony_ci  format: FunctionPrototypeBind(_format, null, '\\'),
9011cb0ef41Sopenharmony_ci
9021cb0ef41Sopenharmony_ci  /**
9031cb0ef41Sopenharmony_ci   * @param {string} path
9041cb0ef41Sopenharmony_ci   * @returns {{
9051cb0ef41Sopenharmony_ci   *  dir: string;
9061cb0ef41Sopenharmony_ci   *  root: string;
9071cb0ef41Sopenharmony_ci   *  base: string;
9081cb0ef41Sopenharmony_ci   *  name: string;
9091cb0ef41Sopenharmony_ci   *  ext: string;
9101cb0ef41Sopenharmony_ci   *  }}
9111cb0ef41Sopenharmony_ci   */
9121cb0ef41Sopenharmony_ci  parse(path) {
9131cb0ef41Sopenharmony_ci    validateString(path, 'path');
9141cb0ef41Sopenharmony_ci
9151cb0ef41Sopenharmony_ci    const ret = { root: '', dir: '', base: '', ext: '', name: '' };
9161cb0ef41Sopenharmony_ci    if (path.length === 0)
9171cb0ef41Sopenharmony_ci      return ret;
9181cb0ef41Sopenharmony_ci
9191cb0ef41Sopenharmony_ci    const len = path.length;
9201cb0ef41Sopenharmony_ci    let rootEnd = 0;
9211cb0ef41Sopenharmony_ci    let code = StringPrototypeCharCodeAt(path, 0);
9221cb0ef41Sopenharmony_ci
9231cb0ef41Sopenharmony_ci    if (len === 1) {
9241cb0ef41Sopenharmony_ci      if (isPathSeparator(code)) {
9251cb0ef41Sopenharmony_ci        // `path` contains just a path separator, exit early to avoid
9261cb0ef41Sopenharmony_ci        // unnecessary work
9271cb0ef41Sopenharmony_ci        ret.root = ret.dir = path;
9281cb0ef41Sopenharmony_ci        return ret;
9291cb0ef41Sopenharmony_ci      }
9301cb0ef41Sopenharmony_ci      ret.base = ret.name = path;
9311cb0ef41Sopenharmony_ci      return ret;
9321cb0ef41Sopenharmony_ci    }
9331cb0ef41Sopenharmony_ci    // Try to match a root
9341cb0ef41Sopenharmony_ci    if (isPathSeparator(code)) {
9351cb0ef41Sopenharmony_ci      // Possible UNC root
9361cb0ef41Sopenharmony_ci
9371cb0ef41Sopenharmony_ci      rootEnd = 1;
9381cb0ef41Sopenharmony_ci      if (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) {
9391cb0ef41Sopenharmony_ci        // Matched double path separator at beginning
9401cb0ef41Sopenharmony_ci        let j = 2;
9411cb0ef41Sopenharmony_ci        let last = j;
9421cb0ef41Sopenharmony_ci        // Match 1 or more non-path separators
9431cb0ef41Sopenharmony_ci        while (j < len &&
9441cb0ef41Sopenharmony_ci               !isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
9451cb0ef41Sopenharmony_ci          j++;
9461cb0ef41Sopenharmony_ci        }
9471cb0ef41Sopenharmony_ci        if (j < len && j !== last) {
9481cb0ef41Sopenharmony_ci          // Matched!
9491cb0ef41Sopenharmony_ci          last = j;
9501cb0ef41Sopenharmony_ci          // Match 1 or more path separators
9511cb0ef41Sopenharmony_ci          while (j < len &&
9521cb0ef41Sopenharmony_ci                 isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
9531cb0ef41Sopenharmony_ci            j++;
9541cb0ef41Sopenharmony_ci          }
9551cb0ef41Sopenharmony_ci          if (j < len && j !== last) {
9561cb0ef41Sopenharmony_ci            // Matched!
9571cb0ef41Sopenharmony_ci            last = j;
9581cb0ef41Sopenharmony_ci            // Match 1 or more non-path separators
9591cb0ef41Sopenharmony_ci            while (j < len &&
9601cb0ef41Sopenharmony_ci                   !isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
9611cb0ef41Sopenharmony_ci              j++;
9621cb0ef41Sopenharmony_ci            }
9631cb0ef41Sopenharmony_ci            if (j === len) {
9641cb0ef41Sopenharmony_ci              // We matched a UNC root only
9651cb0ef41Sopenharmony_ci              rootEnd = j;
9661cb0ef41Sopenharmony_ci            } else if (j !== last) {
9671cb0ef41Sopenharmony_ci              // We matched a UNC root with leftovers
9681cb0ef41Sopenharmony_ci              rootEnd = j + 1;
9691cb0ef41Sopenharmony_ci            }
9701cb0ef41Sopenharmony_ci          }
9711cb0ef41Sopenharmony_ci        }
9721cb0ef41Sopenharmony_ci      }
9731cb0ef41Sopenharmony_ci    } else if (isWindowsDeviceRoot(code) &&
9741cb0ef41Sopenharmony_ci               StringPrototypeCharCodeAt(path, 1) === CHAR_COLON) {
9751cb0ef41Sopenharmony_ci      // Possible device root
9761cb0ef41Sopenharmony_ci      if (len <= 2) {
9771cb0ef41Sopenharmony_ci        // `path` contains just a drive root, exit early to avoid
9781cb0ef41Sopenharmony_ci        // unnecessary work
9791cb0ef41Sopenharmony_ci        ret.root = ret.dir = path;
9801cb0ef41Sopenharmony_ci        return ret;
9811cb0ef41Sopenharmony_ci      }
9821cb0ef41Sopenharmony_ci      rootEnd = 2;
9831cb0ef41Sopenharmony_ci      if (isPathSeparator(StringPrototypeCharCodeAt(path, 2))) {
9841cb0ef41Sopenharmony_ci        if (len === 3) {
9851cb0ef41Sopenharmony_ci          // `path` contains just a drive root, exit early to avoid
9861cb0ef41Sopenharmony_ci          // unnecessary work
9871cb0ef41Sopenharmony_ci          ret.root = ret.dir = path;
9881cb0ef41Sopenharmony_ci          return ret;
9891cb0ef41Sopenharmony_ci        }
9901cb0ef41Sopenharmony_ci        rootEnd = 3;
9911cb0ef41Sopenharmony_ci      }
9921cb0ef41Sopenharmony_ci    }
9931cb0ef41Sopenharmony_ci    if (rootEnd > 0)
9941cb0ef41Sopenharmony_ci      ret.root = StringPrototypeSlice(path, 0, rootEnd);
9951cb0ef41Sopenharmony_ci
9961cb0ef41Sopenharmony_ci    let startDot = -1;
9971cb0ef41Sopenharmony_ci    let startPart = rootEnd;
9981cb0ef41Sopenharmony_ci    let end = -1;
9991cb0ef41Sopenharmony_ci    let matchedSlash = true;
10001cb0ef41Sopenharmony_ci    let i = path.length - 1;
10011cb0ef41Sopenharmony_ci
10021cb0ef41Sopenharmony_ci    // Track the state of characters (if any) we see before our first dot and
10031cb0ef41Sopenharmony_ci    // after any path separator we find
10041cb0ef41Sopenharmony_ci    let preDotState = 0;
10051cb0ef41Sopenharmony_ci
10061cb0ef41Sopenharmony_ci    // Get non-dir info
10071cb0ef41Sopenharmony_ci    for (; i >= rootEnd; --i) {
10081cb0ef41Sopenharmony_ci      code = StringPrototypeCharCodeAt(path, i);
10091cb0ef41Sopenharmony_ci      if (isPathSeparator(code)) {
10101cb0ef41Sopenharmony_ci        // If we reached a path separator that was not part of a set of path
10111cb0ef41Sopenharmony_ci        // separators at the end of the string, stop now
10121cb0ef41Sopenharmony_ci        if (!matchedSlash) {
10131cb0ef41Sopenharmony_ci          startPart = i + 1;
10141cb0ef41Sopenharmony_ci          break;
10151cb0ef41Sopenharmony_ci        }
10161cb0ef41Sopenharmony_ci        continue;
10171cb0ef41Sopenharmony_ci      }
10181cb0ef41Sopenharmony_ci      if (end === -1) {
10191cb0ef41Sopenharmony_ci        // We saw the first non-path separator, mark this as the end of our
10201cb0ef41Sopenharmony_ci        // extension
10211cb0ef41Sopenharmony_ci        matchedSlash = false;
10221cb0ef41Sopenharmony_ci        end = i + 1;
10231cb0ef41Sopenharmony_ci      }
10241cb0ef41Sopenharmony_ci      if (code === CHAR_DOT) {
10251cb0ef41Sopenharmony_ci        // If this is our first dot, mark it as the start of our extension
10261cb0ef41Sopenharmony_ci        if (startDot === -1)
10271cb0ef41Sopenharmony_ci          startDot = i;
10281cb0ef41Sopenharmony_ci        else if (preDotState !== 1)
10291cb0ef41Sopenharmony_ci          preDotState = 1;
10301cb0ef41Sopenharmony_ci      } else if (startDot !== -1) {
10311cb0ef41Sopenharmony_ci        // We saw a non-dot and non-path separator before our dot, so we should
10321cb0ef41Sopenharmony_ci        // have a good chance at having a non-empty extension
10331cb0ef41Sopenharmony_ci        preDotState = -1;
10341cb0ef41Sopenharmony_ci      }
10351cb0ef41Sopenharmony_ci    }
10361cb0ef41Sopenharmony_ci
10371cb0ef41Sopenharmony_ci    if (end !== -1) {
10381cb0ef41Sopenharmony_ci      if (startDot === -1 ||
10391cb0ef41Sopenharmony_ci          // We saw a non-dot character immediately before the dot
10401cb0ef41Sopenharmony_ci          preDotState === 0 ||
10411cb0ef41Sopenharmony_ci          // The (right-most) trimmed path component is exactly '..'
10421cb0ef41Sopenharmony_ci          (preDotState === 1 &&
10431cb0ef41Sopenharmony_ci           startDot === end - 1 &&
10441cb0ef41Sopenharmony_ci           startDot === startPart + 1)) {
10451cb0ef41Sopenharmony_ci        ret.base = ret.name = StringPrototypeSlice(path, startPart, end);
10461cb0ef41Sopenharmony_ci      } else {
10471cb0ef41Sopenharmony_ci        ret.name = StringPrototypeSlice(path, startPart, startDot);
10481cb0ef41Sopenharmony_ci        ret.base = StringPrototypeSlice(path, startPart, end);
10491cb0ef41Sopenharmony_ci        ret.ext = StringPrototypeSlice(path, startDot, end);
10501cb0ef41Sopenharmony_ci      }
10511cb0ef41Sopenharmony_ci    }
10521cb0ef41Sopenharmony_ci
10531cb0ef41Sopenharmony_ci    // If the directory is the root, use the entire root as the `dir` including
10541cb0ef41Sopenharmony_ci    // the trailing slash if any (`C:\abc` -> `C:\`). Otherwise, strip out the
10551cb0ef41Sopenharmony_ci    // trailing slash (`C:\abc\def` -> `C:\abc`).
10561cb0ef41Sopenharmony_ci    if (startPart > 0 && startPart !== rootEnd)
10571cb0ef41Sopenharmony_ci      ret.dir = StringPrototypeSlice(path, 0, startPart - 1);
10581cb0ef41Sopenharmony_ci    else
10591cb0ef41Sopenharmony_ci      ret.dir = ret.root;
10601cb0ef41Sopenharmony_ci
10611cb0ef41Sopenharmony_ci    return ret;
10621cb0ef41Sopenharmony_ci  },
10631cb0ef41Sopenharmony_ci
10641cb0ef41Sopenharmony_ci  sep: '\\',
10651cb0ef41Sopenharmony_ci  delimiter: ';',
10661cb0ef41Sopenharmony_ci  win32: null,
10671cb0ef41Sopenharmony_ci  posix: null,
10681cb0ef41Sopenharmony_ci};
10691cb0ef41Sopenharmony_ci
10701cb0ef41Sopenharmony_ciconst posixCwd = (() => {
10711cb0ef41Sopenharmony_ci  if (platformIsWin32) {
10721cb0ef41Sopenharmony_ci    // Converts Windows' backslash path separators to POSIX forward slashes
10731cb0ef41Sopenharmony_ci    // and truncates any drive indicator
10741cb0ef41Sopenharmony_ci    const regexp = /\\/g;
10751cb0ef41Sopenharmony_ci    return () => {
10761cb0ef41Sopenharmony_ci      const cwd = StringPrototypeReplace(process.cwd(), regexp, '/');
10771cb0ef41Sopenharmony_ci      return StringPrototypeSlice(cwd, StringPrototypeIndexOf(cwd, '/'));
10781cb0ef41Sopenharmony_ci    };
10791cb0ef41Sopenharmony_ci  }
10801cb0ef41Sopenharmony_ci
10811cb0ef41Sopenharmony_ci  // We're already on POSIX, no need for any transformations
10821cb0ef41Sopenharmony_ci  return () => process.cwd();
10831cb0ef41Sopenharmony_ci})();
10841cb0ef41Sopenharmony_ci
10851cb0ef41Sopenharmony_ciconst posix = {
10861cb0ef41Sopenharmony_ci  /**
10871cb0ef41Sopenharmony_ci   * path.resolve([from ...], to)
10881cb0ef41Sopenharmony_ci   * @param {...string} args
10891cb0ef41Sopenharmony_ci   * @returns {string}
10901cb0ef41Sopenharmony_ci   */
10911cb0ef41Sopenharmony_ci  resolve(...args) {
10921cb0ef41Sopenharmony_ci    let resolvedPath = '';
10931cb0ef41Sopenharmony_ci    let resolvedAbsolute = false;
10941cb0ef41Sopenharmony_ci
10951cb0ef41Sopenharmony_ci    for (let i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) {
10961cb0ef41Sopenharmony_ci      const path = i >= 0 ? args[i] : posixCwd();
10971cb0ef41Sopenharmony_ci      validateString(path, `paths[${i}]`);
10981cb0ef41Sopenharmony_ci
10991cb0ef41Sopenharmony_ci      // Skip empty entries
11001cb0ef41Sopenharmony_ci      if (path.length === 0) {
11011cb0ef41Sopenharmony_ci        continue;
11021cb0ef41Sopenharmony_ci      }
11031cb0ef41Sopenharmony_ci
11041cb0ef41Sopenharmony_ci      resolvedPath = `${path}/${resolvedPath}`;
11051cb0ef41Sopenharmony_ci      resolvedAbsolute =
11061cb0ef41Sopenharmony_ci        StringPrototypeCharCodeAt(path, 0) === CHAR_FORWARD_SLASH;
11071cb0ef41Sopenharmony_ci    }
11081cb0ef41Sopenharmony_ci
11091cb0ef41Sopenharmony_ci    // At this point the path should be resolved to a full absolute path, but
11101cb0ef41Sopenharmony_ci    // handle relative paths to be safe (might happen when process.cwd() fails)
11111cb0ef41Sopenharmony_ci
11121cb0ef41Sopenharmony_ci    // Normalize the path
11131cb0ef41Sopenharmony_ci    resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/',
11141cb0ef41Sopenharmony_ci                                   isPosixPathSeparator);
11151cb0ef41Sopenharmony_ci
11161cb0ef41Sopenharmony_ci    if (resolvedAbsolute) {
11171cb0ef41Sopenharmony_ci      return `/${resolvedPath}`;
11181cb0ef41Sopenharmony_ci    }
11191cb0ef41Sopenharmony_ci    return resolvedPath.length > 0 ? resolvedPath : '.';
11201cb0ef41Sopenharmony_ci  },
11211cb0ef41Sopenharmony_ci
11221cb0ef41Sopenharmony_ci  /**
11231cb0ef41Sopenharmony_ci   * @param {string} path
11241cb0ef41Sopenharmony_ci   * @returns {string}
11251cb0ef41Sopenharmony_ci   */
11261cb0ef41Sopenharmony_ci  normalize(path) {
11271cb0ef41Sopenharmony_ci    validateString(path, 'path');
11281cb0ef41Sopenharmony_ci
11291cb0ef41Sopenharmony_ci    if (path.length === 0)
11301cb0ef41Sopenharmony_ci      return '.';
11311cb0ef41Sopenharmony_ci
11321cb0ef41Sopenharmony_ci    const isAbsolute =
11331cb0ef41Sopenharmony_ci      StringPrototypeCharCodeAt(path, 0) === CHAR_FORWARD_SLASH;
11341cb0ef41Sopenharmony_ci    const trailingSeparator =
11351cb0ef41Sopenharmony_ci      StringPrototypeCharCodeAt(path, path.length - 1) === CHAR_FORWARD_SLASH;
11361cb0ef41Sopenharmony_ci
11371cb0ef41Sopenharmony_ci    // Normalize the path
11381cb0ef41Sopenharmony_ci    path = normalizeString(path, !isAbsolute, '/', isPosixPathSeparator);
11391cb0ef41Sopenharmony_ci
11401cb0ef41Sopenharmony_ci    if (path.length === 0) {
11411cb0ef41Sopenharmony_ci      if (isAbsolute)
11421cb0ef41Sopenharmony_ci        return '/';
11431cb0ef41Sopenharmony_ci      return trailingSeparator ? './' : '.';
11441cb0ef41Sopenharmony_ci    }
11451cb0ef41Sopenharmony_ci    if (trailingSeparator)
11461cb0ef41Sopenharmony_ci      path += '/';
11471cb0ef41Sopenharmony_ci
11481cb0ef41Sopenharmony_ci    return isAbsolute ? `/${path}` : path;
11491cb0ef41Sopenharmony_ci  },
11501cb0ef41Sopenharmony_ci
11511cb0ef41Sopenharmony_ci  /**
11521cb0ef41Sopenharmony_ci   * @param {string} path
11531cb0ef41Sopenharmony_ci   * @returns {boolean}
11541cb0ef41Sopenharmony_ci   */
11551cb0ef41Sopenharmony_ci  isAbsolute(path) {
11561cb0ef41Sopenharmony_ci    validateString(path, 'path');
11571cb0ef41Sopenharmony_ci    return path.length > 0 &&
11581cb0ef41Sopenharmony_ci           StringPrototypeCharCodeAt(path, 0) === CHAR_FORWARD_SLASH;
11591cb0ef41Sopenharmony_ci  },
11601cb0ef41Sopenharmony_ci
11611cb0ef41Sopenharmony_ci  /**
11621cb0ef41Sopenharmony_ci   * @param {...string} args
11631cb0ef41Sopenharmony_ci   * @returns {string}
11641cb0ef41Sopenharmony_ci   */
11651cb0ef41Sopenharmony_ci  join(...args) {
11661cb0ef41Sopenharmony_ci    if (args.length === 0)
11671cb0ef41Sopenharmony_ci      return '.';
11681cb0ef41Sopenharmony_ci    let joined;
11691cb0ef41Sopenharmony_ci    for (let i = 0; i < args.length; ++i) {
11701cb0ef41Sopenharmony_ci      const arg = args[i];
11711cb0ef41Sopenharmony_ci      validateString(arg, 'path');
11721cb0ef41Sopenharmony_ci      if (arg.length > 0) {
11731cb0ef41Sopenharmony_ci        if (joined === undefined)
11741cb0ef41Sopenharmony_ci          joined = arg;
11751cb0ef41Sopenharmony_ci        else
11761cb0ef41Sopenharmony_ci          joined += `/${arg}`;
11771cb0ef41Sopenharmony_ci      }
11781cb0ef41Sopenharmony_ci    }
11791cb0ef41Sopenharmony_ci    if (joined === undefined)
11801cb0ef41Sopenharmony_ci      return '.';
11811cb0ef41Sopenharmony_ci    return posix.normalize(joined);
11821cb0ef41Sopenharmony_ci  },
11831cb0ef41Sopenharmony_ci
11841cb0ef41Sopenharmony_ci  /**
11851cb0ef41Sopenharmony_ci   * @param {string} from
11861cb0ef41Sopenharmony_ci   * @param {string} to
11871cb0ef41Sopenharmony_ci   * @returns {string}
11881cb0ef41Sopenharmony_ci   */
11891cb0ef41Sopenharmony_ci  relative(from, to) {
11901cb0ef41Sopenharmony_ci    validateString(from, 'from');
11911cb0ef41Sopenharmony_ci    validateString(to, 'to');
11921cb0ef41Sopenharmony_ci
11931cb0ef41Sopenharmony_ci    if (from === to)
11941cb0ef41Sopenharmony_ci      return '';
11951cb0ef41Sopenharmony_ci
11961cb0ef41Sopenharmony_ci    // Trim leading forward slashes.
11971cb0ef41Sopenharmony_ci    from = posix.resolve(from);
11981cb0ef41Sopenharmony_ci    to = posix.resolve(to);
11991cb0ef41Sopenharmony_ci
12001cb0ef41Sopenharmony_ci    if (from === to)
12011cb0ef41Sopenharmony_ci      return '';
12021cb0ef41Sopenharmony_ci
12031cb0ef41Sopenharmony_ci    const fromStart = 1;
12041cb0ef41Sopenharmony_ci    const fromEnd = from.length;
12051cb0ef41Sopenharmony_ci    const fromLen = fromEnd - fromStart;
12061cb0ef41Sopenharmony_ci    const toStart = 1;
12071cb0ef41Sopenharmony_ci    const toLen = to.length - toStart;
12081cb0ef41Sopenharmony_ci
12091cb0ef41Sopenharmony_ci    // Compare paths to find the longest common path from root
12101cb0ef41Sopenharmony_ci    const length = (fromLen < toLen ? fromLen : toLen);
12111cb0ef41Sopenharmony_ci    let lastCommonSep = -1;
12121cb0ef41Sopenharmony_ci    let i = 0;
12131cb0ef41Sopenharmony_ci    for (; i < length; i++) {
12141cb0ef41Sopenharmony_ci      const fromCode = StringPrototypeCharCodeAt(from, fromStart + i);
12151cb0ef41Sopenharmony_ci      if (fromCode !== StringPrototypeCharCodeAt(to, toStart + i))
12161cb0ef41Sopenharmony_ci        break;
12171cb0ef41Sopenharmony_ci      else if (fromCode === CHAR_FORWARD_SLASH)
12181cb0ef41Sopenharmony_ci        lastCommonSep = i;
12191cb0ef41Sopenharmony_ci    }
12201cb0ef41Sopenharmony_ci    if (i === length) {
12211cb0ef41Sopenharmony_ci      if (toLen > length) {
12221cb0ef41Sopenharmony_ci        if (StringPrototypeCharCodeAt(to, toStart + i) === CHAR_FORWARD_SLASH) {
12231cb0ef41Sopenharmony_ci          // We get here if `from` is the exact base path for `to`.
12241cb0ef41Sopenharmony_ci          // For example: from='/foo/bar'; to='/foo/bar/baz'
12251cb0ef41Sopenharmony_ci          return StringPrototypeSlice(to, toStart + i + 1);
12261cb0ef41Sopenharmony_ci        }
12271cb0ef41Sopenharmony_ci        if (i === 0) {
12281cb0ef41Sopenharmony_ci          // We get here if `from` is the root
12291cb0ef41Sopenharmony_ci          // For example: from='/'; to='/foo'
12301cb0ef41Sopenharmony_ci          return StringPrototypeSlice(to, toStart + i);
12311cb0ef41Sopenharmony_ci        }
12321cb0ef41Sopenharmony_ci      } else if (fromLen > length) {
12331cb0ef41Sopenharmony_ci        if (StringPrototypeCharCodeAt(from, fromStart + i) ===
12341cb0ef41Sopenharmony_ci            CHAR_FORWARD_SLASH) {
12351cb0ef41Sopenharmony_ci          // We get here if `to` is the exact base path for `from`.
12361cb0ef41Sopenharmony_ci          // For example: from='/foo/bar/baz'; to='/foo/bar'
12371cb0ef41Sopenharmony_ci          lastCommonSep = i;
12381cb0ef41Sopenharmony_ci        } else if (i === 0) {
12391cb0ef41Sopenharmony_ci          // We get here if `to` is the root.
12401cb0ef41Sopenharmony_ci          // For example: from='/foo/bar'; to='/'
12411cb0ef41Sopenharmony_ci          lastCommonSep = 0;
12421cb0ef41Sopenharmony_ci        }
12431cb0ef41Sopenharmony_ci      }
12441cb0ef41Sopenharmony_ci    }
12451cb0ef41Sopenharmony_ci
12461cb0ef41Sopenharmony_ci    let out = '';
12471cb0ef41Sopenharmony_ci    // Generate the relative path based on the path difference between `to`
12481cb0ef41Sopenharmony_ci    // and `from`.
12491cb0ef41Sopenharmony_ci    for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
12501cb0ef41Sopenharmony_ci      if (i === fromEnd ||
12511cb0ef41Sopenharmony_ci          StringPrototypeCharCodeAt(from, i) === CHAR_FORWARD_SLASH) {
12521cb0ef41Sopenharmony_ci        out += out.length === 0 ? '..' : '/..';
12531cb0ef41Sopenharmony_ci      }
12541cb0ef41Sopenharmony_ci    }
12551cb0ef41Sopenharmony_ci
12561cb0ef41Sopenharmony_ci    // Lastly, append the rest of the destination (`to`) path that comes after
12571cb0ef41Sopenharmony_ci    // the common path parts.
12581cb0ef41Sopenharmony_ci    return `${out}${StringPrototypeSlice(to, toStart + lastCommonSep)}`;
12591cb0ef41Sopenharmony_ci  },
12601cb0ef41Sopenharmony_ci
12611cb0ef41Sopenharmony_ci  /**
12621cb0ef41Sopenharmony_ci   * @param {string} path
12631cb0ef41Sopenharmony_ci   * @returns {string}
12641cb0ef41Sopenharmony_ci   */
12651cb0ef41Sopenharmony_ci  toNamespacedPath(path) {
12661cb0ef41Sopenharmony_ci    // Non-op on posix systems
12671cb0ef41Sopenharmony_ci    return path;
12681cb0ef41Sopenharmony_ci  },
12691cb0ef41Sopenharmony_ci
12701cb0ef41Sopenharmony_ci  /**
12711cb0ef41Sopenharmony_ci   * @param {string} path
12721cb0ef41Sopenharmony_ci   * @returns {string}
12731cb0ef41Sopenharmony_ci   */
12741cb0ef41Sopenharmony_ci  dirname(path) {
12751cb0ef41Sopenharmony_ci    validateString(path, 'path');
12761cb0ef41Sopenharmony_ci    if (path.length === 0)
12771cb0ef41Sopenharmony_ci      return '.';
12781cb0ef41Sopenharmony_ci    const hasRoot = StringPrototypeCharCodeAt(path, 0) === CHAR_FORWARD_SLASH;
12791cb0ef41Sopenharmony_ci    let end = -1;
12801cb0ef41Sopenharmony_ci    let matchedSlash = true;
12811cb0ef41Sopenharmony_ci    for (let i = path.length - 1; i >= 1; --i) {
12821cb0ef41Sopenharmony_ci      if (StringPrototypeCharCodeAt(path, i) === CHAR_FORWARD_SLASH) {
12831cb0ef41Sopenharmony_ci        if (!matchedSlash) {
12841cb0ef41Sopenharmony_ci          end = i;
12851cb0ef41Sopenharmony_ci          break;
12861cb0ef41Sopenharmony_ci        }
12871cb0ef41Sopenharmony_ci      } else {
12881cb0ef41Sopenharmony_ci        // We saw the first non-path separator
12891cb0ef41Sopenharmony_ci        matchedSlash = false;
12901cb0ef41Sopenharmony_ci      }
12911cb0ef41Sopenharmony_ci    }
12921cb0ef41Sopenharmony_ci
12931cb0ef41Sopenharmony_ci    if (end === -1)
12941cb0ef41Sopenharmony_ci      return hasRoot ? '/' : '.';
12951cb0ef41Sopenharmony_ci    if (hasRoot && end === 1)
12961cb0ef41Sopenharmony_ci      return '//';
12971cb0ef41Sopenharmony_ci    return StringPrototypeSlice(path, 0, end);
12981cb0ef41Sopenharmony_ci  },
12991cb0ef41Sopenharmony_ci
13001cb0ef41Sopenharmony_ci  /**
13011cb0ef41Sopenharmony_ci   * @param {string} path
13021cb0ef41Sopenharmony_ci   * @param {string} [suffix]
13031cb0ef41Sopenharmony_ci   * @returns {string}
13041cb0ef41Sopenharmony_ci   */
13051cb0ef41Sopenharmony_ci  basename(path, suffix) {
13061cb0ef41Sopenharmony_ci    if (suffix !== undefined)
13071cb0ef41Sopenharmony_ci      validateString(suffix, 'ext');
13081cb0ef41Sopenharmony_ci    validateString(path, 'path');
13091cb0ef41Sopenharmony_ci
13101cb0ef41Sopenharmony_ci    let start = 0;
13111cb0ef41Sopenharmony_ci    let end = -1;
13121cb0ef41Sopenharmony_ci    let matchedSlash = true;
13131cb0ef41Sopenharmony_ci
13141cb0ef41Sopenharmony_ci    if (suffix !== undefined && suffix.length > 0 && suffix.length <= path.length) {
13151cb0ef41Sopenharmony_ci      if (suffix === path)
13161cb0ef41Sopenharmony_ci        return '';
13171cb0ef41Sopenharmony_ci      let extIdx = suffix.length - 1;
13181cb0ef41Sopenharmony_ci      let firstNonSlashEnd = -1;
13191cb0ef41Sopenharmony_ci      for (let i = path.length - 1; i >= 0; --i) {
13201cb0ef41Sopenharmony_ci        const code = StringPrototypeCharCodeAt(path, i);
13211cb0ef41Sopenharmony_ci        if (code === CHAR_FORWARD_SLASH) {
13221cb0ef41Sopenharmony_ci          // If we reached a path separator that was not part of a set of path
13231cb0ef41Sopenharmony_ci          // separators at the end of the string, stop now
13241cb0ef41Sopenharmony_ci          if (!matchedSlash) {
13251cb0ef41Sopenharmony_ci            start = i + 1;
13261cb0ef41Sopenharmony_ci            break;
13271cb0ef41Sopenharmony_ci          }
13281cb0ef41Sopenharmony_ci        } else {
13291cb0ef41Sopenharmony_ci          if (firstNonSlashEnd === -1) {
13301cb0ef41Sopenharmony_ci            // We saw the first non-path separator, remember this index in case
13311cb0ef41Sopenharmony_ci            // we need it if the extension ends up not matching
13321cb0ef41Sopenharmony_ci            matchedSlash = false;
13331cb0ef41Sopenharmony_ci            firstNonSlashEnd = i + 1;
13341cb0ef41Sopenharmony_ci          }
13351cb0ef41Sopenharmony_ci          if (extIdx >= 0) {
13361cb0ef41Sopenharmony_ci            // Try to match the explicit extension
13371cb0ef41Sopenharmony_ci            if (code === StringPrototypeCharCodeAt(suffix, extIdx)) {
13381cb0ef41Sopenharmony_ci              if (--extIdx === -1) {
13391cb0ef41Sopenharmony_ci                // We matched the extension, so mark this as the end of our path
13401cb0ef41Sopenharmony_ci                // component
13411cb0ef41Sopenharmony_ci                end = i;
13421cb0ef41Sopenharmony_ci              }
13431cb0ef41Sopenharmony_ci            } else {
13441cb0ef41Sopenharmony_ci              // Extension does not match, so our result is the entire path
13451cb0ef41Sopenharmony_ci              // component
13461cb0ef41Sopenharmony_ci              extIdx = -1;
13471cb0ef41Sopenharmony_ci              end = firstNonSlashEnd;
13481cb0ef41Sopenharmony_ci            }
13491cb0ef41Sopenharmony_ci          }
13501cb0ef41Sopenharmony_ci        }
13511cb0ef41Sopenharmony_ci      }
13521cb0ef41Sopenharmony_ci
13531cb0ef41Sopenharmony_ci      if (start === end)
13541cb0ef41Sopenharmony_ci        end = firstNonSlashEnd;
13551cb0ef41Sopenharmony_ci      else if (end === -1)
13561cb0ef41Sopenharmony_ci        end = path.length;
13571cb0ef41Sopenharmony_ci      return StringPrototypeSlice(path, start, end);
13581cb0ef41Sopenharmony_ci    }
13591cb0ef41Sopenharmony_ci    for (let i = path.length - 1; i >= 0; --i) {
13601cb0ef41Sopenharmony_ci      if (StringPrototypeCharCodeAt(path, i) === CHAR_FORWARD_SLASH) {
13611cb0ef41Sopenharmony_ci        // If we reached a path separator that was not part of a set of path
13621cb0ef41Sopenharmony_ci        // separators at the end of the string, stop now
13631cb0ef41Sopenharmony_ci        if (!matchedSlash) {
13641cb0ef41Sopenharmony_ci          start = i + 1;
13651cb0ef41Sopenharmony_ci          break;
13661cb0ef41Sopenharmony_ci        }
13671cb0ef41Sopenharmony_ci      } else if (end === -1) {
13681cb0ef41Sopenharmony_ci        // We saw the first non-path separator, mark this as the end of our
13691cb0ef41Sopenharmony_ci        // path component
13701cb0ef41Sopenharmony_ci        matchedSlash = false;
13711cb0ef41Sopenharmony_ci        end = i + 1;
13721cb0ef41Sopenharmony_ci      }
13731cb0ef41Sopenharmony_ci    }
13741cb0ef41Sopenharmony_ci
13751cb0ef41Sopenharmony_ci    if (end === -1)
13761cb0ef41Sopenharmony_ci      return '';
13771cb0ef41Sopenharmony_ci    return StringPrototypeSlice(path, start, end);
13781cb0ef41Sopenharmony_ci  },
13791cb0ef41Sopenharmony_ci
13801cb0ef41Sopenharmony_ci  /**
13811cb0ef41Sopenharmony_ci   * @param {string} path
13821cb0ef41Sopenharmony_ci   * @returns {string}
13831cb0ef41Sopenharmony_ci   */
13841cb0ef41Sopenharmony_ci  extname(path) {
13851cb0ef41Sopenharmony_ci    validateString(path, 'path');
13861cb0ef41Sopenharmony_ci    let startDot = -1;
13871cb0ef41Sopenharmony_ci    let startPart = 0;
13881cb0ef41Sopenharmony_ci    let end = -1;
13891cb0ef41Sopenharmony_ci    let matchedSlash = true;
13901cb0ef41Sopenharmony_ci    // Track the state of characters (if any) we see before our first dot and
13911cb0ef41Sopenharmony_ci    // after any path separator we find
13921cb0ef41Sopenharmony_ci    let preDotState = 0;
13931cb0ef41Sopenharmony_ci    for (let i = path.length - 1; i >= 0; --i) {
13941cb0ef41Sopenharmony_ci      const code = StringPrototypeCharCodeAt(path, i);
13951cb0ef41Sopenharmony_ci      if (code === CHAR_FORWARD_SLASH) {
13961cb0ef41Sopenharmony_ci        // If we reached a path separator that was not part of a set of path
13971cb0ef41Sopenharmony_ci        // separators at the end of the string, stop now
13981cb0ef41Sopenharmony_ci        if (!matchedSlash) {
13991cb0ef41Sopenharmony_ci          startPart = i + 1;
14001cb0ef41Sopenharmony_ci          break;
14011cb0ef41Sopenharmony_ci        }
14021cb0ef41Sopenharmony_ci        continue;
14031cb0ef41Sopenharmony_ci      }
14041cb0ef41Sopenharmony_ci      if (end === -1) {
14051cb0ef41Sopenharmony_ci        // We saw the first non-path separator, mark this as the end of our
14061cb0ef41Sopenharmony_ci        // extension
14071cb0ef41Sopenharmony_ci        matchedSlash = false;
14081cb0ef41Sopenharmony_ci        end = i + 1;
14091cb0ef41Sopenharmony_ci      }
14101cb0ef41Sopenharmony_ci      if (code === CHAR_DOT) {
14111cb0ef41Sopenharmony_ci        // If this is our first dot, mark it as the start of our extension
14121cb0ef41Sopenharmony_ci        if (startDot === -1)
14131cb0ef41Sopenharmony_ci          startDot = i;
14141cb0ef41Sopenharmony_ci        else if (preDotState !== 1)
14151cb0ef41Sopenharmony_ci          preDotState = 1;
14161cb0ef41Sopenharmony_ci      } else if (startDot !== -1) {
14171cb0ef41Sopenharmony_ci        // We saw a non-dot and non-path separator before our dot, so we should
14181cb0ef41Sopenharmony_ci        // have a good chance at having a non-empty extension
14191cb0ef41Sopenharmony_ci        preDotState = -1;
14201cb0ef41Sopenharmony_ci      }
14211cb0ef41Sopenharmony_ci    }
14221cb0ef41Sopenharmony_ci
14231cb0ef41Sopenharmony_ci    if (startDot === -1 ||
14241cb0ef41Sopenharmony_ci        end === -1 ||
14251cb0ef41Sopenharmony_ci        // We saw a non-dot character immediately before the dot
14261cb0ef41Sopenharmony_ci        preDotState === 0 ||
14271cb0ef41Sopenharmony_ci        // The (right-most) trimmed path component is exactly '..'
14281cb0ef41Sopenharmony_ci        (preDotState === 1 &&
14291cb0ef41Sopenharmony_ci         startDot === end - 1 &&
14301cb0ef41Sopenharmony_ci         startDot === startPart + 1)) {
14311cb0ef41Sopenharmony_ci      return '';
14321cb0ef41Sopenharmony_ci    }
14331cb0ef41Sopenharmony_ci    return StringPrototypeSlice(path, startDot, end);
14341cb0ef41Sopenharmony_ci  },
14351cb0ef41Sopenharmony_ci
14361cb0ef41Sopenharmony_ci  format: FunctionPrototypeBind(_format, null, '/'),
14371cb0ef41Sopenharmony_ci
14381cb0ef41Sopenharmony_ci  /**
14391cb0ef41Sopenharmony_ci   * @param {string} path
14401cb0ef41Sopenharmony_ci   * @returns {{
14411cb0ef41Sopenharmony_ci   *   dir: string;
14421cb0ef41Sopenharmony_ci   *   root: string;
14431cb0ef41Sopenharmony_ci   *   base: string;
14441cb0ef41Sopenharmony_ci   *   name: string;
14451cb0ef41Sopenharmony_ci   *   ext: string;
14461cb0ef41Sopenharmony_ci   *   }}
14471cb0ef41Sopenharmony_ci   */
14481cb0ef41Sopenharmony_ci  parse(path) {
14491cb0ef41Sopenharmony_ci    validateString(path, 'path');
14501cb0ef41Sopenharmony_ci
14511cb0ef41Sopenharmony_ci    const ret = { root: '', dir: '', base: '', ext: '', name: '' };
14521cb0ef41Sopenharmony_ci    if (path.length === 0)
14531cb0ef41Sopenharmony_ci      return ret;
14541cb0ef41Sopenharmony_ci    const isAbsolute =
14551cb0ef41Sopenharmony_ci      StringPrototypeCharCodeAt(path, 0) === CHAR_FORWARD_SLASH;
14561cb0ef41Sopenharmony_ci    let start;
14571cb0ef41Sopenharmony_ci    if (isAbsolute) {
14581cb0ef41Sopenharmony_ci      ret.root = '/';
14591cb0ef41Sopenharmony_ci      start = 1;
14601cb0ef41Sopenharmony_ci    } else {
14611cb0ef41Sopenharmony_ci      start = 0;
14621cb0ef41Sopenharmony_ci    }
14631cb0ef41Sopenharmony_ci    let startDot = -1;
14641cb0ef41Sopenharmony_ci    let startPart = 0;
14651cb0ef41Sopenharmony_ci    let end = -1;
14661cb0ef41Sopenharmony_ci    let matchedSlash = true;
14671cb0ef41Sopenharmony_ci    let i = path.length - 1;
14681cb0ef41Sopenharmony_ci
14691cb0ef41Sopenharmony_ci    // Track the state of characters (if any) we see before our first dot and
14701cb0ef41Sopenharmony_ci    // after any path separator we find
14711cb0ef41Sopenharmony_ci    let preDotState = 0;
14721cb0ef41Sopenharmony_ci
14731cb0ef41Sopenharmony_ci    // Get non-dir info
14741cb0ef41Sopenharmony_ci    for (; i >= start; --i) {
14751cb0ef41Sopenharmony_ci      const code = StringPrototypeCharCodeAt(path, i);
14761cb0ef41Sopenharmony_ci      if (code === CHAR_FORWARD_SLASH) {
14771cb0ef41Sopenharmony_ci        // If we reached a path separator that was not part of a set of path
14781cb0ef41Sopenharmony_ci        // separators at the end of the string, stop now
14791cb0ef41Sopenharmony_ci        if (!matchedSlash) {
14801cb0ef41Sopenharmony_ci          startPart = i + 1;
14811cb0ef41Sopenharmony_ci          break;
14821cb0ef41Sopenharmony_ci        }
14831cb0ef41Sopenharmony_ci        continue;
14841cb0ef41Sopenharmony_ci      }
14851cb0ef41Sopenharmony_ci      if (end === -1) {
14861cb0ef41Sopenharmony_ci        // We saw the first non-path separator, mark this as the end of our
14871cb0ef41Sopenharmony_ci        // extension
14881cb0ef41Sopenharmony_ci        matchedSlash = false;
14891cb0ef41Sopenharmony_ci        end = i + 1;
14901cb0ef41Sopenharmony_ci      }
14911cb0ef41Sopenharmony_ci      if (code === CHAR_DOT) {
14921cb0ef41Sopenharmony_ci        // If this is our first dot, mark it as the start of our extension
14931cb0ef41Sopenharmony_ci        if (startDot === -1)
14941cb0ef41Sopenharmony_ci          startDot = i;
14951cb0ef41Sopenharmony_ci        else if (preDotState !== 1)
14961cb0ef41Sopenharmony_ci          preDotState = 1;
14971cb0ef41Sopenharmony_ci      } else if (startDot !== -1) {
14981cb0ef41Sopenharmony_ci        // We saw a non-dot and non-path separator before our dot, so we should
14991cb0ef41Sopenharmony_ci        // have a good chance at having a non-empty extension
15001cb0ef41Sopenharmony_ci        preDotState = -1;
15011cb0ef41Sopenharmony_ci      }
15021cb0ef41Sopenharmony_ci    }
15031cb0ef41Sopenharmony_ci
15041cb0ef41Sopenharmony_ci    if (end !== -1) {
15051cb0ef41Sopenharmony_ci      const start = startPart === 0 && isAbsolute ? 1 : startPart;
15061cb0ef41Sopenharmony_ci      if (startDot === -1 ||
15071cb0ef41Sopenharmony_ci          // We saw a non-dot character immediately before the dot
15081cb0ef41Sopenharmony_ci          preDotState === 0 ||
15091cb0ef41Sopenharmony_ci          // The (right-most) trimmed path component is exactly '..'
15101cb0ef41Sopenharmony_ci          (preDotState === 1 &&
15111cb0ef41Sopenharmony_ci          startDot === end - 1 &&
15121cb0ef41Sopenharmony_ci          startDot === startPart + 1)) {
15131cb0ef41Sopenharmony_ci        ret.base = ret.name = StringPrototypeSlice(path, start, end);
15141cb0ef41Sopenharmony_ci      } else {
15151cb0ef41Sopenharmony_ci        ret.name = StringPrototypeSlice(path, start, startDot);
15161cb0ef41Sopenharmony_ci        ret.base = StringPrototypeSlice(path, start, end);
15171cb0ef41Sopenharmony_ci        ret.ext = StringPrototypeSlice(path, startDot, end);
15181cb0ef41Sopenharmony_ci      }
15191cb0ef41Sopenharmony_ci    }
15201cb0ef41Sopenharmony_ci
15211cb0ef41Sopenharmony_ci    if (startPart > 0)
15221cb0ef41Sopenharmony_ci      ret.dir = StringPrototypeSlice(path, 0, startPart - 1);
15231cb0ef41Sopenharmony_ci    else if (isAbsolute)
15241cb0ef41Sopenharmony_ci      ret.dir = '/';
15251cb0ef41Sopenharmony_ci
15261cb0ef41Sopenharmony_ci    return ret;
15271cb0ef41Sopenharmony_ci  },
15281cb0ef41Sopenharmony_ci
15291cb0ef41Sopenharmony_ci  sep: '/',
15301cb0ef41Sopenharmony_ci  delimiter: ':',
15311cb0ef41Sopenharmony_ci  win32: null,
15321cb0ef41Sopenharmony_ci  posix: null,
15331cb0ef41Sopenharmony_ci};
15341cb0ef41Sopenharmony_ci
15351cb0ef41Sopenharmony_ciposix.win32 = win32.win32 = win32;
15361cb0ef41Sopenharmony_ciposix.posix = win32.posix = posix;
15371cb0ef41Sopenharmony_ci
15381cb0ef41Sopenharmony_ci// Legacy internal API, docs-only deprecated: DEP0080
15391cb0ef41Sopenharmony_ciwin32._makeLong = win32.toNamespacedPath;
15401cb0ef41Sopenharmony_ciposix._makeLong = posix.toNamespacedPath;
15411cb0ef41Sopenharmony_ci
15421cb0ef41Sopenharmony_cimodule.exports = platformIsWin32 ? win32 : posix;
1543