Module

std/path/_util.ts

Deno standard library
Go to Latest
File
// Copyright 2018-2022 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 type { FormatInputPathObject } from "./_interface.ts";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): void { 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 namesexport 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 _format( sep: string, pathObject: FormatInputPathObject,): string { const dir: string | undefined = pathObject.dir || pathObject.root; const base: string = pathObject.base || (pathObject.name || "") + (pathObject.ext || ""); if (!dir) return base; if (dir === pathObject.root) return dir + base; return dir + sep + base;}
const WHITESPACE_ENCODINGS: Record<string, string> = { "\u0009": "%09", "\u000A": "%0A", "\u000B": "%0B", "\u000C": "%0C", "\u000D": "%0D", "\u0020": "%20",};
export function encodeWhitespace(string: string): string { return string.replaceAll(/[\s]/g, (c) => { return WHITESPACE_ENCODINGS[c] ?? c; });}