From 57b6fdb2eb743260a771489b98eb9e691ccad236 Mon Sep 17 00:00:00 2001 From: Max Graey Date: Thu, 24 Jan 2019 21:06:24 +0200 Subject: [PATCH] Clean up path module (denoland/deno_std#149) Original: https://github.com/denoland/deno_std/commit/47e6fc775aaf1c4970e4098822aa40c3203286ae --- fs/path/constants.ts | 3 +- fs/path/interface.ts | 24 +----- fs/path/mod.ts | 195 +++++++++++++++++++++---------------------- 3 files changed, 97 insertions(+), 125 deletions(-) diff --git a/fs/path/constants.ts b/fs/path/constants.ts index b440be9cca..ce121f9ace 100644 --- a/fs/path/constants.ts +++ b/fs/path/constants.ts @@ -3,8 +3,6 @@ import { platform } from "deno"; -const isWindows = platform.os === "win"; - // Alphabet chars. export const CHAR_UPPERCASE_A = 65; /* A */ export const CHAR_LOWERCASE_A = 97; /* a */ @@ -50,4 +48,5 @@ export const CHAR_EQUAL = 61; /* = */ export const CHAR_0 = 48; /* 0 */ export const CHAR_9 = 57; /* 9 */ +export const isWindows = platform.os === "win"; export const EOL = isWindows ? "\r\n" : "\n"; diff --git a/fs/path/interface.ts b/fs/path/interface.ts index 84a3030ff0..a140a4ca57 100644 --- a/fs/path/interface.ts +++ b/fs/path/interface.ts @@ -23,25 +23,5 @@ export interface ParsedPath { */ name: string; } -export interface FormatInputPathObject { - /** - * The root of the path such as '/' or 'c:\' - */ - root?: string; - /** - * The full directory path such as '/home/user/dir' or 'c:\path\dir' - */ - dir?: string; - /** - * The file name including extension (if any) such as 'index.html' - */ - base?: string; - /** - * The file extension (if any) such as '.html' - */ - ext?: string; - /** - * The file name without extension (if any) such as 'index' - */ - name?: string; -} + +export type FormatInputPathObject = Partial diff --git a/fs/path/mod.ts b/fs/path/mod.ts index 4201c52ad1..114c904a25 100644 --- a/fs/path/mod.ts +++ b/fs/path/mod.ts @@ -1,7 +1,10 @@ // Copyright the Browserify authors. MIT License. // Ported from https://github.com/browserify/path-browserify/ +import { cwd, env } from "deno"; +import { FormatInputPathObject, ParsedPath } from "./interface.ts"; import { + isWindows, CHAR_UPPERCASE_A, CHAR_LOWERCASE_A, CHAR_UPPERCASE_Z, @@ -12,10 +15,8 @@ import { CHAR_COLON, CHAR_QUESTION_MARK } from "./constants.ts"; -import { cwd, env, platform } from "deno"; -import { FormatInputPathObject, ParsedPath } from "./interface.ts"; -function assertPath(path: string) { +function assertPath(path: string): void { if (typeof path !== "string") { throw new TypeError( `Path must be a string. Received ${JSON.stringify(path)}` @@ -23,18 +24,18 @@ function assertPath(path: string) { } } -function isPathSeparator(code: number) { - return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; -} - -function isPosixPathSeparator(code: number) { +function isPosixPathSeparator(code: number): boolean { return code === CHAR_FORWARD_SLASH; } -function isWindowsDeviceRoot(code: number) { +function isPathSeparator(code: number): boolean { + return isPosixPathSeparator(code) || code === CHAR_BACKWARD_SLASH; +} + +function isWindowsDeviceRoot(code: number): boolean { return ( - (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || - (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z) + (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z) || + (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) ); } @@ -44,14 +45,14 @@ function normalizeString( allowAboveRoot: boolean, separator: string, isPathSeparator: (code: number) => boolean -) { +): string { let res = ""; let lastSegmentLength = 0; let lastSlash = -1; let dots = 0; let code: number; - for (let i = 0; i <= path.length; ++i) { - if (i < path.length) code = path.charCodeAt(i); + 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; @@ -106,30 +107,26 @@ function normalizeString( return res; } -function _format(sep: string, pathObject: FormatInputPathObject) { - const dir = pathObject.dir || pathObject.root; - const base = +function _format(sep: string, pathObject: FormatInputPathObject): string { + const dir: string | null = pathObject.dir || pathObject.root; + const base: string = pathObject.base || (pathObject.name || "") + (pathObject.ext || ""); - if (!dir) { - return base; - } - if (dir === pathObject.root) { - return dir + base; - } + if (!dir) return base; + if (dir === pathObject.root) return dir + base; return dir + sep + base; } export const win32 = { // path.resolve([from ...], to) - resolve: function resolve(...pathSegments: string[]) { + resolve(...pathSegments: string[]): string { let resolvedDevice = ""; let resolvedTail = ""; let resolvedAbsolute = false; - for (let i = arguments.length - 1; i >= -1; i--) { + for (let i = pathSegments.length - 1; i >= -1; i--) { let path: string; if (i >= 0) { - path = arguments[i]; + path = pathSegments[i]; } else if (!resolvedDevice) { path = cwd(); } else { @@ -152,12 +149,11 @@ export const win32 = { assertPath(path); - // Skip empty entries - if (path.length === 0) { - continue; - } + const len = path.length; + + // Skip empty entries + if (len === 0) continue; - let len = path.length; let rootEnd = 0; let device = ""; let isAbsolute = false; @@ -249,9 +245,7 @@ export const win32 = { resolvedAbsolute = isAbsolute; } - if (resolvedDevice.length > 0 && resolvedAbsolute) { - break; - } + if (resolvedAbsolute && resolvedDevice.length > 0) break; } // At this point the path should be resolved to a full absolute path, @@ -271,7 +265,7 @@ export const win32 = { ); }, - normalize: function normalize(path: string) { + normalize(path: string): string { assertPath(path); const len = path.length; if (len === 0) return "."; @@ -384,7 +378,7 @@ export const win32 = { } }, - isAbsolute: function isAbsolute(path: string) { + isAbsolute(path: string): boolean { assertPath(path); const len = path.length; if (len === 0) return false; @@ -402,17 +396,18 @@ export const win32 = { return false; }, - join: function join(...paths: string[]) { - if (arguments.length === 0) return "."; + join(...paths: string[]): string { + const pathsCount = paths.length; + if (pathsCount === 0) return "."; let joined: string; let firstPart: string; - for (let i = 0; i < arguments.length; ++i) { - let arg = arguments[i]; - assertPath(arg); - if (arg.length > 0) { - if (joined === undefined) joined = firstPart = arg; - else joined += `\\${arg}`; + for (let i = 0; i < pathsCount; ++i) { + let path = paths[i]; + assertPath(path); + if (path.length > 0) { + if (joined === undefined) joined = firstPart = path; + else joined += `\\${path}`; } } @@ -466,7 +461,7 @@ export const win32 = { // from = 'C:\\orandea\\test\\aaa' // to = 'C:\\orandea\\impl\\bbb' // The output of the function should be: '..\\..\\impl\\bbb' - relative: function relative(from: string, to: string) { + relative(from: string, to: string): string { assertPath(from); assertPath(to); @@ -484,11 +479,11 @@ export const win32 = { // Trim any leading backslashes let fromStart = 0; - for (; fromStart < from.length; ++fromStart) { + let fromEnd = from.length; + for (; fromStart < fromEnd; ++fromStart) { if (from.charCodeAt(fromStart) !== CHAR_BACKWARD_SLASH) break; } // Trim trailing backslashes (applicable to UNC paths only) - let fromEnd = from.length; for (; fromEnd - 1 > fromStart; --fromEnd) { if (from.charCodeAt(fromEnd - 1) !== CHAR_BACKWARD_SLASH) break; } @@ -496,11 +491,11 @@ export const win32 = { // Trim any leading backslashes let toStart = 0; - for (; toStart < to.length; ++toStart) { + let toEnd = to.length; + for (; toStart < toEnd; ++toStart) { if (to.charCodeAt(toStart) !== CHAR_BACKWARD_SLASH) break; } // Trim trailing backslashes (applicable to UNC paths only) - let toEnd = to.length; for (; toEnd - 1 > toStart; --toEnd) { if (to.charCodeAt(toEnd - 1) !== CHAR_BACKWARD_SLASH) break; } @@ -570,13 +565,10 @@ export const win32 = { } }, - toNamespacedPath: function toNamespacedPath(path: string) { + toNamespacedPath(path: string): string { // Note: this will *probably* throw somewhere. if (typeof path !== "string") return path; - - if (path.length === 0) { - return ""; - } + if (path.length === 0) return ""; const resolvedPath = win32.resolve(path); @@ -607,7 +599,7 @@ export const win32 = { return path; }, - dirname: function dirname(path: string) { + dirname(path: string): string { assertPath(path); const len = path.length; if (len === 0) return "."; @@ -695,10 +687,12 @@ export const win32 = { return path.slice(0, end); }, - basename: function basename(path: string, ext = "") { + basename(path: string, ext = ""): string { if (ext !== undefined && typeof ext !== "string") throw new TypeError('"ext" argument must be a string'); + assertPath(path); + let start = 0; let end = -1; let matchedSlash = true; @@ -777,7 +771,7 @@ export const win32 = { } }, - extname: function extname(path: string) { + extname(path: string): string { assertPath(path); let start = 0; let startDot = -1; @@ -841,7 +835,7 @@ export const win32 = { return path.slice(startDot, end); }, - format: function format(pathObject: FormatInputPathObject) { + format(pathObject: FormatInputPathObject): string { if (pathObject === null || typeof pathObject !== "object") { throw new TypeError( `The "pathObject" argument must be of type Object. Received type ${typeof pathObject}` @@ -850,13 +844,14 @@ export const win32 = { return _format("\\", pathObject); }, - parse: function parse(path: string) { + parse(path: string): ParsedPath { assertPath(path); let ret = { root: "", dir: "", base: "", ext: "", name: "" } as ParsedPath; - if (path.length === 0) return ret; - let len = path.length; + const len = path.length; + if (len === 0) return ret; + let rootEnd = 0; let code = path.charCodeAt(0); @@ -985,15 +980,15 @@ export const win32 = { } else { ret.name = path.slice(startPart, startDot); ret.base = path.slice(startPart, end); - ret.ext = path.slice(startDot, end); + ret.ext = path.slice(startDot, end); } // If the directory is the root, use the entire root as the `dir` including // the trailing slash if any (`C:\abc` -> `C:\`). Otherwise, strip out the // trailing slash (`C:\abc\def` -> `C:\abc`). - if (startPart > 0 && startPart !== rootEnd) + if (startPart > 0 && startPart !== rootEnd) { ret.dir = path.slice(0, startPart - 1); - else ret.dir = ret.root; + } else ret.dir = ret.root; return ret; }, @@ -1006,16 +1001,15 @@ export const win32 = { export const posix = { // path.resolve([from ...], to) - resolve: function resolve(...pathSegments: string[]) { + resolve(...pathSegments: string[]): string { let resolvedPath = ""; let resolvedAbsolute = false; - for (let i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + for (let i = pathSegments.length - 1; i >= -1 && !resolvedAbsolute; i--) { let path: string; - if (i >= 0) path = arguments[i]; - else { - path = cwd(); - } + + if (i >= 0) path = pathSegments[i]; + else path = cwd(); assertPath(path); @@ -1042,14 +1036,11 @@ export const posix = { if (resolvedAbsolute) { if (resolvedPath.length > 0) return `/${resolvedPath}`; else return "/"; - } else if (resolvedPath.length > 0) { - return resolvedPath; - } else { - return "."; - } + } else if (resolvedPath.length > 0) return resolvedPath; + else return "."; }, - normalize: function normalize(path: string) { + normalize(path: string): string { assertPath(path); if (path.length === 0) return "."; @@ -1068,27 +1059,27 @@ export const posix = { return path; }, - isAbsolute: function isAbsolute(path: string) { + isAbsolute(path: string): boolean { assertPath(path); return path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH; }, - join: function join(...paths: string[]) { - if (arguments.length === 0) return "."; - let joined: string; - for (let i = 0; i < arguments.length; ++i) { - let arg = arguments[i]; - assertPath(arg); - if (arg.length > 0) { - if (joined === undefined) joined = arg; - else joined += `/${arg}`; + join(...paths: string[]): string { + if (paths.length === 0) return "."; + let joined: string | undefined; + for (let i = 0, len = paths.length; i < len; ++i) { + let path = paths[i]; + assertPath(path); + if (path.length > 0) { + if (!joined) joined = path; + else joined += `/${path}`; } } - if (joined === undefined) return "."; + if (!joined) return "."; return posix.normalize(joined); }, - relative: function relative(from: string, to: string) { + relative(from: string, to: string): string { assertPath(from); assertPath(to); @@ -1101,18 +1092,18 @@ export const posix = { // Trim any leading backslashes let fromStart = 1; - for (; fromStart < from.length; ++fromStart) { + let fromEnd = from.length; + for (; fromStart < fromEnd; ++fromStart) { if (from.charCodeAt(fromStart) !== CHAR_FORWARD_SLASH) break; } - let fromEnd = from.length; let fromLen = fromEnd - fromStart; // Trim any leading backslashes let toStart = 1; - for (; toStart < to.length; ++toStart) { + const toEnd = to.length; + for (; toStart < toEnd; ++toStart) { if (to.charCodeAt(toStart) !== CHAR_FORWARD_SLASH) break; } - let toEnd = to.length; let toLen = toEnd - toStart; // Compare paths to find the longest common path from root @@ -1170,12 +1161,12 @@ export const posix = { } }, - toNamespacedPath: function toNamespacedPath(path: string) { + toNamespacedPath(path: string): string { // Non-op on posix systems return path; }, - dirname: function dirname(path: string) { + dirname(path: string): string { assertPath(path); if (path.length === 0) return "."; const hasRoot = path.charCodeAt(0) === CHAR_FORWARD_SLASH; @@ -1198,7 +1189,7 @@ export const posix = { return path.slice(0, end); }, - basename: function basename(path: string, ext = "") { + basename(path: string, ext = ""): string { if (ext !== undefined && typeof ext !== "string") throw new TypeError('"ext" argument must be a string'); assertPath(path); @@ -1271,7 +1262,7 @@ export const posix = { } }, - extname: function extname(path: string) { + extname(path: string): string { assertPath(path); let startDot = -1; let startPart = 0; @@ -1321,7 +1312,7 @@ export const posix = { return path.slice(startDot, end); }, - format: function format(pathObject: FormatInputPathObject) { + format(pathObject: FormatInputPathObject): string { if (pathObject === null || typeof pathObject !== "object") { throw new TypeError( `The "pathObject" argument must be of type Object. Received type ${typeof pathObject}` @@ -1330,7 +1321,7 @@ export const posix = { return _format("/", pathObject); }, - parse: function parse(path: string) { + parse(path: string): ParsedPath { assertPath(path); let ret = { root: "", dir: "", base: "", ext: "", name: "" } as ParsedPath; @@ -1391,9 +1382,11 @@ export const posix = { (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) ) { if (end !== -1) { - if (startPart === 0 && isAbsolute) + if (startPart === 0 && isAbsolute) { ret.base = ret.name = path.slice(1, end); - else ret.base = ret.name = path.slice(startPart, end); + } else { + ret.base = ret.name = path.slice(startPart, end); + } } } else { if (startPart === 0 && isAbsolute) { @@ -1421,7 +1414,7 @@ export const posix = { posix.win32 = win32.win32 = win32; posix.posix = win32.posix = posix; -const module = platform.os === "win" ? win32 : posix; +const module = isWindows ? win32 : posix; export const resolve = module.resolve; export const normalize = module.normalize;