Partial migration of some shared vpath functionality to core
This commit is contained in:
parent
c9c562afac
commit
8424c4d1ab
4 changed files with 96 additions and 181 deletions
|
@ -1928,6 +1928,9 @@ namespace ts {
|
|||
return text1 ? Comparison.GreaterThan : Comparison.LessThan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize path separators.
|
||||
*/
|
||||
export function normalizeSlashes(path: string): string {
|
||||
return path.replace(/\\/g, "/");
|
||||
}
|
||||
|
@ -1968,27 +1971,6 @@ namespace ts {
|
|||
* we expect the host to correctly handle paths in our specified format.
|
||||
*/
|
||||
export const directorySeparator = "/";
|
||||
const directorySeparatorCharCode = CharacterCodes.slash;
|
||||
function getNormalizedParts(normalizedSlashedPath: string, rootLength: number): string[] {
|
||||
const parts = normalizedSlashedPath.substr(rootLength).split(directorySeparator);
|
||||
const normalized: string[] = [];
|
||||
for (const part of parts) {
|
||||
if (part !== ".") {
|
||||
if (part === ".." && normalized.length > 0 && lastOrUndefined(normalized) !== "..") {
|
||||
normalized.pop();
|
||||
}
|
||||
else {
|
||||
// A part may be an empty string (which is 'falsy') if the path had consecutive slashes,
|
||||
// e.g. "path//file.ts". Drop these before re-joining the parts.
|
||||
if (part) {
|
||||
normalized.push(part);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
export function normalizePath(path: string): string {
|
||||
return normalizePathAndParts(path).path;
|
||||
|
@ -1996,23 +1978,16 @@ namespace ts {
|
|||
|
||||
export function normalizePathAndParts(path: string): { path: string, parts: string[] } {
|
||||
path = normalizeSlashes(path);
|
||||
const rootLength = getRootLength(path);
|
||||
const root = path.substr(0, rootLength);
|
||||
const parts = getNormalizedParts(path, rootLength);
|
||||
const [root, ...parts] = reducePathComponents(getPathComponents(path));
|
||||
if (parts.length) {
|
||||
const joinedParts = root + parts.join(directorySeparator);
|
||||
return { path: pathEndsWithDirectorySeparator(path) ? joinedParts + directorySeparator : joinedParts, parts };
|
||||
return { path: hasTrailingDirectorySeparator(path) ? joinedParts + directorySeparator : joinedParts, parts };
|
||||
}
|
||||
else {
|
||||
return { path: root, parts };
|
||||
}
|
||||
}
|
||||
|
||||
/** A path ending with '/' refers to a directory only, never a file. */
|
||||
export function pathEndsWithDirectorySeparator(path: string): boolean {
|
||||
return path.charCodeAt(path.length - 1) === directorySeparatorCharCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path except for its basename. Eg:
|
||||
*
|
||||
|
@ -2085,41 +2060,88 @@ namespace ts {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a path is an absolute path (e.g. starts with `/`, or a dos path
|
||||
* like `c:`, `c:\` or `c:/`).
|
||||
*/
|
||||
export function isRootedDiskPath(path: string) {
|
||||
return path && getRootLength(path) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a path consists only of a path root.
|
||||
*/
|
||||
export function isDiskPathRoot(path: string) {
|
||||
const rootLength = getRootLength(path);
|
||||
return rootLength > 0 && rootLength === path.length;
|
||||
}
|
||||
|
||||
export function convertToRelativePath(absoluteOrRelativePath: string, basePath: string, getCanonicalFileName: (path: string) => string): string {
|
||||
return !isRootedDiskPath(absoluteOrRelativePath)
|
||||
? absoluteOrRelativePath
|
||||
: getRelativePathToDirectoryOrUrl(basePath, absoluteOrRelativePath, basePath, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
|
||||
}
|
||||
|
||||
function normalizedPathComponents(path: string, rootLength: number) {
|
||||
const normalizedParts = getNormalizedParts(path, rootLength);
|
||||
return [path.substr(0, rootLength)].concat(normalizedParts);
|
||||
function pathComponents(path: string, rootLength: number) {
|
||||
const root = path.substring(0, rootLength);
|
||||
const rest = path.substring(rootLength).split(directorySeparator);
|
||||
if (rest.length && !lastOrUndefined(rest)) rest.pop();
|
||||
return [root, ...rest];
|
||||
}
|
||||
|
||||
export function getNormalizedPathComponents(path: string, currentDirectory: string) {
|
||||
path = normalizeSlashes(path);
|
||||
let rootLength = getRootLength(path);
|
||||
if (rootLength === 0) {
|
||||
// If the path is not rooted it is relative to current directory
|
||||
path = combinePaths(normalizeSlashes(currentDirectory), path);
|
||||
rootLength = getRootLength(path);
|
||||
}
|
||||
/**
|
||||
* Parse a path into an array containing a root component (at index 0) and zero or more path
|
||||
* components (at indices > 0). The result is not normalized.
|
||||
* If the path is relative, the root component is `""`.
|
||||
* If the path is absolute, the root component includes the first path separator (`/`).
|
||||
*/
|
||||
export function getPathComponents(path: string, currentDirectory = "") {
|
||||
path = combinePaths(currentDirectory, path);
|
||||
const rootLength = getRootLength(path);
|
||||
return pathComponents(path, rootLength);
|
||||
}
|
||||
|
||||
return normalizedPathComponents(path, rootLength);
|
||||
export function reducePathComponents(components: ReadonlyArray<string>) {
|
||||
const reduced = [components[0]];
|
||||
for (let i = 1; i < components.length; i++) {
|
||||
const component = components[i];
|
||||
if (component === ".") continue;
|
||||
if (component === "..") {
|
||||
if (reduced.length > 1) {
|
||||
if (reduced[reduced.length - 1] !== "..") {
|
||||
reduced.pop();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (reduced[0]) continue;
|
||||
}
|
||||
reduced.push(component);
|
||||
}
|
||||
return reduced;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a path into an array containing a root component (at index 0) and zero or more path
|
||||
* components (at indices > 0). The result is normalized.
|
||||
* If the path is relative, the root component is `""`.
|
||||
* If the path is absolute, the root component includes the first path separator (`/`).
|
||||
*/
|
||||
export function getNormalizedPathComponents(path: string, currentDirectory: string) {
|
||||
return reducePathComponents(getPathComponents(path, currentDirectory));
|
||||
}
|
||||
|
||||
export function getNormalizedAbsolutePath(fileName: string, currentDirectory: string) {
|
||||
return getNormalizedPathFromPathComponents(getNormalizedPathComponents(fileName, currentDirectory));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a parsed path consisting of a root component and zero or more path segments.
|
||||
*/
|
||||
export function getNormalizedPathFromPathComponents(pathComponents: ReadonlyArray<string>) {
|
||||
if (pathComponents && pathComponents.length) {
|
||||
return pathComponents[0] + pathComponents.slice(1).join(directorySeparator);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function getNormalizedPathComponentsOfUrl(url: string) {
|
||||
|
@ -2153,7 +2175,7 @@ namespace ts {
|
|||
// Found the "/" after the website.com so the root is length of http://www.website.com/
|
||||
// and get components after the root normally like any other folder components
|
||||
rootLength = indexOfNextSlash + 1;
|
||||
return normalizedPathComponents(url, rootLength);
|
||||
return reducePathComponents(pathComponents(url, rootLength));
|
||||
}
|
||||
else {
|
||||
// Can't find the host assume the rest of the string as component
|
||||
|
@ -2229,14 +2251,28 @@ namespace ts {
|
|||
return i < 0 ? path : path.substring(i + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines two paths. If a path is absolute, it replaces any previous path.
|
||||
*/
|
||||
export function combinePaths(path1: string, path2: string): string {
|
||||
if (path1) path1 = normalizeSlashes(path1);
|
||||
if (path2) path2 = normalizeSlashes(path2);
|
||||
if (!(path1 && path1.length)) return path2;
|
||||
if (!(path2 && path2.length)) return path1;
|
||||
if (getRootLength(path2) !== 0) return path2;
|
||||
if (path1.charAt(path1.length - 1) === directorySeparator) return path1 + path2;
|
||||
if (hasTrailingDirectorySeparator(path1)) return path1 + path2;
|
||||
return path1 + directorySeparator + path2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a path has a trailing separator (`/` or `\\`).
|
||||
*/
|
||||
export function hasTrailingDirectorySeparator(path: string) {
|
||||
if (path.length === 0) return false;
|
||||
const ch = path.charCodeAt(path.length - 1);
|
||||
return ch === CharacterCodes.slash || ch === CharacterCodes.backslash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a trailing directory separator from a path.
|
||||
* @param path The path.
|
||||
|
@ -2244,7 +2280,7 @@ namespace ts {
|
|||
export function removeTrailingDirectorySeparator(path: Path): Path;
|
||||
export function removeTrailingDirectorySeparator(path: string): string;
|
||||
export function removeTrailingDirectorySeparator(path: string) {
|
||||
if (path.charAt(path.length - 1) === directorySeparator) {
|
||||
if (hasTrailingDirectorySeparator(path)) {
|
||||
return path.substr(0, path.length - 1);
|
||||
}
|
||||
|
||||
|
@ -2258,7 +2294,7 @@ namespace ts {
|
|||
export function ensureTrailingDirectorySeparator(path: Path): Path;
|
||||
export function ensureTrailingDirectorySeparator(path: string): string;
|
||||
export function ensureTrailingDirectorySeparator(path: string) {
|
||||
if (path.charAt(path.length - 1) !== directorySeparator) {
|
||||
if (!hasTrailingDirectorySeparator(path)) {
|
||||
return path + directorySeparator;
|
||||
}
|
||||
|
||||
|
|
|
@ -806,7 +806,7 @@ namespace ts {
|
|||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Loading_module_as_file_Slash_folder_candidate_module_location_0_target_file_type_1, candidate, Extensions[extensions]);
|
||||
}
|
||||
if (!pathEndsWithDirectorySeparator(candidate)) {
|
||||
if (!hasTrailingDirectorySeparator(candidate)) {
|
||||
if (!onlyRecordFailures) {
|
||||
const parentOfCandidate = getDirectoryPath(candidate);
|
||||
if (!directoryProbablyExists(parentOfCandidate, state.host)) {
|
||||
|
|
|
@ -1,17 +1,4 @@
|
|||
namespace vpath {
|
||||
/**
|
||||
* Virtual path separator.
|
||||
*/
|
||||
export import sep = ts.directorySeparator;
|
||||
|
||||
/**
|
||||
* Normalize path separators.
|
||||
*/
|
||||
export import normalizeSeparators = ts.normalizeSlashes;
|
||||
// export function normalizeSeparators(path: string): string {
|
||||
// return ts.normalizeSlashes(path);
|
||||
// }
|
||||
|
||||
const invalidRootComponentRegExp = /^(?!(\/|\/\/\w+\/|[a-zA-Z]:\/?|)$)/;
|
||||
const invalidNavigableComponentRegExp = /[:*?"<>|]/;
|
||||
const invalidNonNavigableComponentRegExp = /^\.{1,2}$|[:*?"<>|]/;
|
||||
|
@ -93,103 +80,26 @@ namespace vpath {
|
|||
return true;
|
||||
}
|
||||
|
||||
const absolutePathRegExp = /^[\\/]([\\/](.*?[\\/](.*?[\\/])?)?)?|^[a-zA-Z]:[\\/]?|^\w+:\/{2}[^\\/]*\/?/;
|
||||
import getRootLength = ts.getRootLength;
|
||||
|
||||
// NOTE: this differs from `ts.getRootLength` in that it doesn't support URIs.
|
||||
function getRootLength(path: string) {
|
||||
const match = absolutePathRegExp.exec(path);
|
||||
return match ? match[0].length : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a path is an absolute path (e.g. starts with `/`, `\\`, or a dos path
|
||||
* like `c:`).
|
||||
*/
|
||||
export import sep = ts.directorySeparator;
|
||||
export import normalizeSeparators = ts.normalizeSlashes;
|
||||
export import isAbsolute = ts.isRootedDiskPath;
|
||||
// export function isAbsolute(path: string) {
|
||||
// return absolutePathRegExp.test(path);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Determines whether a path consists only of a path root.
|
||||
*/
|
||||
export function isRoot(path: string) {
|
||||
const rootLength = getRootLength(path);
|
||||
return rootLength > 0 && rootLength === path.length;
|
||||
}
|
||||
|
||||
const trailingSeperatorRegExp = /[\\/]$/;
|
||||
|
||||
/**
|
||||
* Determines whether a path has a trailing separator (`/`).
|
||||
*/
|
||||
export function hasTrailingSeparator(path: string) {
|
||||
return trailingSeperatorRegExp.test(path) && !isRoot(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a trailing separator (`/`) to a path if it doesn't have one.
|
||||
*/
|
||||
export import isRoot = ts.isDiskPathRoot;
|
||||
export import hasTrailingSeparator = ts.hasTrailingDirectorySeparator;
|
||||
export import addTrailingSeparator = ts.ensureTrailingDirectorySeparator;
|
||||
// export function addTrailingSeparator(path: string) {
|
||||
// return !trailingSeperatorRegExp.test(path) && path ? path + "/" : path;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Removes a trailing separator (`/`) from a path if it has one.
|
||||
*/
|
||||
export import removeTrailingSeparator = ts.removeTrailingDirectorySeparator;
|
||||
// export function removeTrailingSeparator(path: string) {
|
||||
// return trailingSeperatorRegExp.test(path) && !isRoot(path) ? path.slice(0, -1) : path;
|
||||
// }
|
||||
|
||||
function reduce(components: ReadonlyArray<string>) {
|
||||
const normalized = [components[0]];
|
||||
for (let i = 1; i < components.length; i++) {
|
||||
const component = components[i];
|
||||
if (component === ".") continue;
|
||||
if (component === "..") {
|
||||
if (normalized.length > 1) {
|
||||
if (normalized[normalized.length - 1] !== "..") {
|
||||
normalized.pop();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (normalized[0]) continue;
|
||||
}
|
||||
normalized.push(component);
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
export import normalize = ts.normalizePath;
|
||||
export import combine = ts.combinePaths;
|
||||
export import parse = ts.getPathComponents;
|
||||
export import reduce = ts.reducePathComponents;
|
||||
export import format = ts.getNormalizedPathFromPathComponents;
|
||||
|
||||
/**
|
||||
* Normalize a path containing path traversal components (`.` or `..`).
|
||||
* Combines and normalizes two paths.
|
||||
*/
|
||||
export function normalize(path: string): string {
|
||||
const components = reduce(parse(path));
|
||||
return components.length > 1 && hasTrailingSeparator(path) ? format(components) + sep : format(components);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines two or more paths. If a path is absolute, it replaces any previous path.
|
||||
*/
|
||||
export function combine(path: string, ...paths: string[]) {
|
||||
path = normalizeSeparators(path);
|
||||
for (const name of paths) {
|
||||
path = ts.combinePaths(path, normalizeSeparators(name));
|
||||
// name = normalizeSeparators(name);
|
||||
// if (name.length === 0) continue;
|
||||
// path = path.length === 0 || isAbsolute(name) ? name :
|
||||
// addTrailingSeparator(path) + name;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines and normalizes two or more paths.
|
||||
*/
|
||||
export function resolve(path: string, ...paths: string[]) {
|
||||
return normalize(combine(path, ...paths));
|
||||
export function resolve(path1: string, path2: string) {
|
||||
return normalize(combine(path1, path2));
|
||||
}
|
||||
|
||||
// NOTE: this differs from `ts.getRelativePathToDirectoryOrUrl` in that it requires both paths
|
||||
|
@ -322,32 +232,6 @@ namespace vpath {
|
|||
return ignoreCase ? beneathCaseInsensitive(ancestor, descendant) : beneathCaseSensitive(ancestor, descendant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a path into a root component and zero or more path segments.
|
||||
* If the path is relative, the root component is `""`.
|
||||
* If the path is absolute, the root component includes the first path separator (`/`).
|
||||
*/
|
||||
// NOTE: this differs from `ts.getNormalizedPathComponents` due to the fact that `parse` does
|
||||
// not automatically normalize relative paths and does not perform path normalization. This is
|
||||
// necessary to support proper path navigation in `vfs`.
|
||||
export function parse(path: string) {
|
||||
path = normalizeSeparators(path);
|
||||
const rootLength = getRootLength(path);
|
||||
const root = path.substring(0, rootLength);
|
||||
const rest = path.substring(rootLength).split(/\/+/g);
|
||||
if (rest.length && !rest[rest.length - 1]) rest.pop();
|
||||
return [root, ...rest.map(component => component.trim())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a parsed path consisting of a root component and zero or more path segments.
|
||||
*/
|
||||
// NOTE: this differs from `ts.getNormalizedPathFromPathComponents` in that this function
|
||||
// always returns a string.
|
||||
export function format(components: ReadonlyArray<string>) {
|
||||
return components.length ? components[0] + components.slice(1).join(sep) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parent directory name of a path.
|
||||
*/
|
||||
|
|
|
@ -1122,11 +1122,6 @@ namespace ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
export function hasTrailingDirectorySeparator(path: string) {
|
||||
const lastCharacter = path.charAt(path.length - 1);
|
||||
return lastCharacter === "/" || lastCharacter === "\\";
|
||||
}
|
||||
|
||||
export function isInReferenceComment(sourceFile: SourceFile, position: number): boolean {
|
||||
return isInComment(sourceFile, position, /*tokenAtPosition*/ undefined, c => {
|
||||
const commentText = sourceFile.text.substring(c.pos, c.end);
|
||||
|
|
Loading…
Reference in a new issue