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