1
0
Fork 0
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:
Max Graey 2019-01-24 21:06:24 +02:00 committed by Ryan Dahl
parent 8ad47e3584
commit 47e6fc775a
3 changed files with 97 additions and 125 deletions

View file

@ -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";

View file

@ -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>

View file

@ -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;