Skip to main content
Home
This release is 47 versions behind 1.1.4 — the latest version of @std/path. Jump to latest
Works with
This package works with Cloudflare Workers, Deno, Browsers
This package works with Cloudflare Workers
This package works with Deno
This package works with Browsers
JSR Score94%
Downloads105,805/wk
Published2 years ago (0.199.0)

Utilities for working with file system paths

// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright the Browserify authors. MIT License. // Ported from https://github.com/browserify/path-browserify/ // This module is browser compatible. import { CHAR_BACKWARD_SLASH, CHAR_DOT, CHAR_FORWARD_SLASH, CHAR_LOWERCASE_A, CHAR_LOWERCASE_Z, CHAR_UPPERCASE_A, CHAR_UPPERCASE_Z, } from "./_constants.ts"; export function assertPath(path: string) { if (typeof path !== "string") { throw new TypeError( `Path must be a string. Received ${JSON.stringify(path)}`, ); } } export function isPosixPathSeparator(code: number): boolean { return code === CHAR_FORWARD_SLASH; } export function isPathSeparator(code: number): boolean { return isPosixPathSeparator(code) || code === CHAR_BACKWARD_SLASH; } export function isWindowsDeviceRoot(code: number): boolean { return ( (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z) || (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) ); } // Resolves . and .. elements in a path with directory names export function normalizeString( path: string, allowAboveRoot: boolean, separator: string, isPathSeparator: (code: number) => boolean, ): string { let res = ""; let lastSegmentLength = 0; let lastSlash = -1; let dots = 0; let code: number | undefined; for (let i = 0, len = path.length; i <= len; ++i) { if (i < len) code = path.charCodeAt(i); else if (isPathSeparator(code!)) break; else code = CHAR_FORWARD_SLASH; if (isPathSeparator(code!)) { if (lastSlash === i - 1 || dots === 1) { // NOOP } else if (lastSlash !== i - 1 && dots === 2) { if ( res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== CHAR_DOT || res.charCodeAt(res.length - 2) !== CHAR_DOT ) { if (res.length > 2) { const lastSlashIndex = res.lastIndexOf(separator); if (lastSlashIndex === -1) { res = ""; lastSegmentLength = 0; } else { res = res.slice(0, lastSlashIndex); lastSegmentLength = res.length - 1 - res.lastIndexOf(separator); } lastSlash = i; dots = 0; continue; } else if (res.length === 2 || res.length === 1) { res = ""; lastSegmentLength = 0; lastSlash = i; dots = 0; continue; } } if (allowAboveRoot) { if (res.length > 0) res += `${separator}..`; else res = ".."; lastSegmentLength = 2; } } else { if (res.length > 0) res += separator + path.slice(lastSlash + 1, i); else res = path.slice(lastSlash + 1, i); lastSegmentLength = i - lastSlash - 1; } lastSlash = i; dots = 0; } else if (code === CHAR_DOT && dots !== -1) { ++dots; } else { dots = -1; } } return res; } export function stripTrailingSeparators( segment: string, isSep: (char: number) => boolean, ): string { if (segment.length <= 1) { return segment; } let end = segment.length; for (let i = segment.length - 1; i > 0; i--) { if (isSep(segment.charCodeAt(i))) { end = i; } else { break; } } return segment.slice(0, end); }