1namespace vpath { 2 export import sep = ts.directorySeparator; 3 export import normalizeSeparators = ts.normalizeSlashes; 4 export import isAbsolute = ts.isRootedDiskPath; 5 export import isRoot = ts.isDiskPathRoot; 6 export import hasTrailingSeparator = ts.hasTrailingDirectorySeparator; 7 export import addTrailingSeparator = ts.ensureTrailingDirectorySeparator; 8 export import removeTrailingSeparator = ts.removeTrailingDirectorySeparator; 9 export import normalize = ts.normalizePath; 10 export import combine = ts.combinePaths; 11 export import parse = ts.getPathComponents; 12 export import reduce = ts.reducePathComponents; 13 export import format = ts.getPathFromPathComponents; 14 export import resolve = ts.resolvePath; 15 export import compare = ts.comparePaths; 16 export import compareCaseSensitive = ts.comparePathsCaseSensitive; 17 export import compareCaseInsensitive = ts.comparePathsCaseInsensitive; 18 export import dirname = ts.getDirectoryPath; 19 export import basename = ts.getBaseFileName; 20 export import extname = ts.getAnyExtensionFromPath; 21 export import relative = ts.getRelativePathFromDirectory; 22 export import beneath = ts.containsPath; 23 export import changeExtension = ts.changeAnyExtension; 24 export import isTypeScript = ts.hasTSFileExtension; 25 export import isJavaScript = ts.hasJSFileExtension; 26 27 const invalidRootComponentRegExp = /^(?!(\/|\/\/\w+\/|[a-zA-Z]:\/?|)$)/; 28 const invalidNavigableComponentRegExp = /[:*?"<>|]/; 29 const invalidNavigableComponentWithWildcardsRegExp = /[:"<>|]/; 30 const invalidNonNavigableComponentRegExp = /^\.{1,2}$|[:*?"<>|]/; 31 const invalidNonNavigableComponentWithWildcardsRegExp = /^\.{1,2}$|[:"<>|]/; 32 const extRegExp = /\.\w+$/; 33 34 export const enum ValidationFlags { 35 None = 0, 36 37 RequireRoot = 1 << 0, 38 RequireDirname = 1 << 1, 39 RequireBasename = 1 << 2, 40 RequireExtname = 1 << 3, 41 RequireTrailingSeparator = 1 << 4, 42 43 AllowRoot = 1 << 5, 44 AllowDirname = 1 << 6, 45 AllowBasename = 1 << 7, 46 AllowExtname = 1 << 8, 47 AllowTrailingSeparator = 1 << 9, 48 AllowNavigation = 1 << 10, 49 AllowWildcard = 1 << 11, 50 51 /** Path must be a valid directory root */ 52 Root = RequireRoot | AllowRoot | AllowTrailingSeparator, 53 54 /** Path must be a absolute */ 55 Absolute = RequireRoot | AllowRoot | AllowDirname | AllowBasename | AllowExtname | AllowTrailingSeparator | AllowNavigation, 56 57 /** Path may be relative or absolute */ 58 RelativeOrAbsolute = AllowRoot | AllowDirname | AllowBasename | AllowExtname | AllowTrailingSeparator | AllowNavigation, 59 60 /** Path may only be a filename */ 61 Basename = RequireBasename | AllowExtname, 62 } 63 64 function validateComponents(components: string[], flags: ValidationFlags, hasTrailingSeparator: boolean) { 65 const hasRoot = !!components[0]; 66 const hasDirname = components.length > 2; 67 const hasBasename = components.length > 1; 68 const hasExtname = hasBasename && extRegExp.test(components[components.length - 1]); 69 const invalidComponentRegExp = flags & ValidationFlags.AllowNavigation 70 ? flags & ValidationFlags.AllowWildcard ? invalidNavigableComponentWithWildcardsRegExp : invalidNavigableComponentRegExp 71 : flags & ValidationFlags.AllowWildcard ? invalidNonNavigableComponentWithWildcardsRegExp : invalidNonNavigableComponentRegExp; 72 73 // Validate required components 74 if (flags & ValidationFlags.RequireRoot && !hasRoot) return false; 75 if (flags & ValidationFlags.RequireDirname && !hasDirname) return false; 76 if (flags & ValidationFlags.RequireBasename && !hasBasename) return false; 77 if (flags & ValidationFlags.RequireExtname && !hasExtname) return false; 78 if (flags & ValidationFlags.RequireTrailingSeparator && !hasTrailingSeparator) return false; 79 80 // Required components indicate allowed components 81 if (flags & ValidationFlags.RequireRoot) flags |= ValidationFlags.AllowRoot; 82 if (flags & ValidationFlags.RequireDirname) flags |= ValidationFlags.AllowDirname; 83 if (flags & ValidationFlags.RequireBasename) flags |= ValidationFlags.AllowBasename; 84 if (flags & ValidationFlags.RequireExtname) flags |= ValidationFlags.AllowExtname; 85 if (flags & ValidationFlags.RequireTrailingSeparator) flags |= ValidationFlags.AllowTrailingSeparator; 86 87 // Validate disallowed components 88 if (~flags & ValidationFlags.AllowRoot && hasRoot) return false; 89 if (~flags & ValidationFlags.AllowDirname && hasDirname) return false; 90 if (~flags & ValidationFlags.AllowBasename && hasBasename) return false; 91 if (~flags & ValidationFlags.AllowExtname && hasExtname) return false; 92 if (~flags & ValidationFlags.AllowTrailingSeparator && hasTrailingSeparator) return false; 93 94 // Validate component strings 95 if (invalidRootComponentRegExp.test(components[0])) return false; 96 for (let i = 1; i < components.length; i++) { 97 if (invalidComponentRegExp.test(components[i])) return false; 98 } 99 100 return true; 101 } 102 103 export function validate(path: string, flags: ValidationFlags = ValidationFlags.RelativeOrAbsolute) { 104 const components = parse(path); 105 const trailing = hasTrailingSeparator(path); 106 if (!validateComponents(components, flags, trailing)) throw vfs.createIOError("ENOENT"); 107 return components.length > 1 && trailing ? format(reduce(components)) + sep : format(reduce(components)); 108 } 109 110 export function isDeclaration(path: string) { 111 return ts.isDeclarationFileName(path); 112 } 113 114 export function isSourceMap(path: string) { 115 return extname(path, ".map", /*ignoreCase*/ false).length > 0; 116 } 117 118 const javaScriptSourceMapExtensions: readonly string[] = [".js.map", ".jsx.map"]; 119 120 export function isJavaScriptSourceMap(path: string) { 121 return extname(path, javaScriptSourceMapExtensions, /*ignoreCase*/ false).length > 0; 122 } 123 124 export function isJson(path: string) { 125 return extname(path, ".json", /*ignoreCase*/ false).length > 0 || extname(path, ".json5", /*ignoreCase*/ false).length > 0; 126 } 127 128 export function isDefaultLibrary(path: string) { 129 return isDeclaration(path) 130 && basename(path).startsWith("lib."); 131 } 132 133 export function isTsConfigFile(path: string): boolean { 134 return path.indexOf("tsconfig") !== -1 && path.indexOf("json") !== -1; 135 } 136} 137