• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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