mirror of
https://github.com/denoland/deno.git
synced 2024-12-29 02:29:06 -05:00
Clean up path module (#149)
This commit is contained in:
parent
8ad47e3584
commit
47e6fc775a
3 changed files with 97 additions and 125 deletions
|
@ -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";
|
||||
|
|
|
@ -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<ParsedPath>
|
||||
|
|
195
fs/path/mod.ts
195
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;
|
||||
|
|
Loading…
Reference in a new issue