UNPKG

8.6 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright Google LLC All Rights Reserved.
5 *
6 * Use of this source code is governed by an MIT-style license that can be
7 * found in the LICENSE file at https://angular.io/license
8 */
9Object.defineProperty(exports, "__esModule", { value: true });
10exports.getSystemPath = exports.asPosixPath = exports.asWindowsPath = exports.path = exports.noCacheNormalize = exports.normalize = exports.resetNormalizeCache = exports.fragment = exports.resolve = exports.relative = exports.isAbsolute = exports.join = exports.dirname = exports.basename = exports.extname = exports.split = exports.NormalizedRoot = exports.NormalizedSep = exports.PathCannotBeFragmentException = exports.PathMustBeAbsoluteException = exports.InvalidPathException = void 0;
11const exception_1 = require("../exception");
12class InvalidPathException extends exception_1.BaseException {
13 constructor(path) {
14 super(`Path ${JSON.stringify(path)} is invalid.`);
15 }
16}
17exports.InvalidPathException = InvalidPathException;
18class PathMustBeAbsoluteException extends exception_1.BaseException {
19 constructor(path) {
20 super(`Path ${JSON.stringify(path)} must be absolute.`);
21 }
22}
23exports.PathMustBeAbsoluteException = PathMustBeAbsoluteException;
24class PathCannotBeFragmentException extends exception_1.BaseException {
25 constructor(path) {
26 super(`Path ${JSON.stringify(path)} cannot be made a fragment.`);
27 }
28}
29exports.PathCannotBeFragmentException = PathCannotBeFragmentException;
30/**
31 * The Separator for normalized path.
32 * @type {Path}
33 */
34exports.NormalizedSep = '/';
35/**
36 * The root of a normalized path.
37 * @type {Path}
38 */
39exports.NormalizedRoot = exports.NormalizedSep;
40/**
41 * Split a path into multiple path fragments. Each fragments except the last one will end with
42 * a path separator.
43 * @param {Path} path The path to split.
44 * @returns {Path[]} An array of path fragments.
45 */
46function split(path) {
47 const fragments = path.split(exports.NormalizedSep).map((x) => fragment(x));
48 if (fragments[fragments.length - 1].length === 0) {
49 fragments.pop();
50 }
51 return fragments;
52}
53exports.split = split;
54/**
55 *
56 */
57function extname(path) {
58 const base = basename(path);
59 const i = base.lastIndexOf('.');
60 if (i < 1) {
61 return '';
62 }
63 else {
64 return base.substr(i);
65 }
66}
67exports.extname = extname;
68/**
69 * Return the basename of the path, as a Path. See path.basename
70 */
71function basename(path) {
72 const i = path.lastIndexOf(exports.NormalizedSep);
73 if (i == -1) {
74 return fragment(path);
75 }
76 else {
77 return fragment(path.substr(path.lastIndexOf(exports.NormalizedSep) + 1));
78 }
79}
80exports.basename = basename;
81/**
82 * Return the dirname of the path, as a Path. See path.dirname
83 */
84function dirname(path) {
85 const index = path.lastIndexOf(exports.NormalizedSep);
86 if (index === -1) {
87 return '';
88 }
89 const endIndex = index === 0 ? 1 : index; // case of file under root: '/file'
90 return normalize(path.substr(0, endIndex));
91}
92exports.dirname = dirname;
93/**
94 * Join multiple paths together, and normalize the result. Accepts strings that will be
95 * normalized as well (but the original must be a path).
96 */
97function join(p1, ...others) {
98 if (others.length > 0) {
99 return normalize((p1 ? p1 + exports.NormalizedSep : '') + others.join(exports.NormalizedSep));
100 }
101 else {
102 return p1;
103 }
104}
105exports.join = join;
106/**
107 * Returns true if a path is absolute.
108 */
109function isAbsolute(p) {
110 return p.startsWith(exports.NormalizedSep);
111}
112exports.isAbsolute = isAbsolute;
113/**
114 * Returns a path such that `join(from, relative(from, to)) == to`.
115 * Both paths must be absolute, otherwise it does not make much sense.
116 */
117function relative(from, to) {
118 if (!isAbsolute(from)) {
119 throw new PathMustBeAbsoluteException(from);
120 }
121 if (!isAbsolute(to)) {
122 throw new PathMustBeAbsoluteException(to);
123 }
124 let p;
125 if (from == to) {
126 p = '';
127 }
128 else {
129 const splitFrom = split(from);
130 const splitTo = split(to);
131 while (splitFrom.length > 0 && splitTo.length > 0 && splitFrom[0] == splitTo[0]) {
132 splitFrom.shift();
133 splitTo.shift();
134 }
135 if (splitFrom.length == 0) {
136 p = splitTo.join(exports.NormalizedSep);
137 }
138 else {
139 p = splitFrom
140 .map(() => '..')
141 .concat(splitTo)
142 .join(exports.NormalizedSep);
143 }
144 }
145 return normalize(p);
146}
147exports.relative = relative;
148/**
149 * Returns a Path that is the resolution of p2, from p1. If p2 is absolute, it will return p2,
150 * otherwise will join both p1 and p2.
151 */
152function resolve(p1, p2) {
153 if (isAbsolute(p2)) {
154 return p2;
155 }
156 else {
157 return join(p1, p2);
158 }
159}
160exports.resolve = resolve;
161function fragment(path) {
162 if (path.indexOf(exports.NormalizedSep) != -1) {
163 throw new PathCannotBeFragmentException(path);
164 }
165 return path;
166}
167exports.fragment = fragment;
168/**
169 * normalize() cache to reduce computation. For now this grows and we never flush it, but in the
170 * future we might want to add a few cache flush to prevent this from growing too large.
171 */
172let normalizedCache = new Map();
173/**
174 * Reset the cache. This is only useful for testing.
175 * @private
176 */
177function resetNormalizeCache() {
178 normalizedCache = new Map();
179}
180exports.resetNormalizeCache = resetNormalizeCache;
181/**
182 * Normalize a string into a Path. This is the only mean to get a Path type from a string that
183 * represents a system path. This method cache the results as real world paths tend to be
184 * duplicated often.
185 * Normalization includes:
186 * - Windows backslashes `\\` are replaced with `/`.
187 * - Windows drivers are replaced with `/X/`, where X is the drive letter.
188 * - Absolute paths starts with `/`.
189 * - Multiple `/` are replaced by a single one.
190 * - Path segments `.` are removed.
191 * - Path segments `..` are resolved.
192 * - If a path is absolute, having a `..` at the start is invalid (and will throw).
193 * @param path The path to be normalized.
194 */
195function normalize(path) {
196 let maybePath = normalizedCache.get(path);
197 if (!maybePath) {
198 maybePath = noCacheNormalize(path);
199 normalizedCache.set(path, maybePath);
200 }
201 return maybePath;
202}
203exports.normalize = normalize;
204/**
205 * The no cache version of the normalize() function. Used for benchmarking and testing.
206 */
207function noCacheNormalize(path) {
208 if (path == '' || path == '.') {
209 return '';
210 }
211 else if (path == exports.NormalizedRoot) {
212 return exports.NormalizedRoot;
213 }
214 // Match absolute windows path.
215 const original = path;
216 if (path.match(/^[A-Z]:[\/\\]/i)) {
217 path = '\\' + path[0] + '\\' + path.substr(3);
218 }
219 // We convert Windows paths as well here.
220 const p = path.split(/[\/\\]/g);
221 let relative = false;
222 let i = 1;
223 // Special case the first one.
224 if (p[0] != '') {
225 p.unshift('.');
226 relative = true;
227 }
228 while (i < p.length) {
229 if (p[i] == '.') {
230 p.splice(i, 1);
231 }
232 else if (p[i] == '..') {
233 if (i < 2 && !relative) {
234 throw new InvalidPathException(original);
235 }
236 else if (i >= 2 && p[i - 1] != '..') {
237 p.splice(i - 1, 2);
238 i--;
239 }
240 else {
241 i++;
242 }
243 }
244 else if (p[i] == '') {
245 p.splice(i, 1);
246 }
247 else {
248 i++;
249 }
250 }
251 if (p.length == 1) {
252 return p[0] == '' ? exports.NormalizedSep : '';
253 }
254 else {
255 if (p[0] == '.') {
256 p.shift();
257 }
258 return p.join(exports.NormalizedSep);
259 }
260}
261exports.noCacheNormalize = noCacheNormalize;
262const path = (strings, ...values) => {
263 return normalize(String.raw(strings, ...values));
264};
265exports.path = path;
266function asWindowsPath(path) {
267 const drive = path.match(/^\/(\w)(?:\/(.*))?$/);
268 if (drive) {
269 const subPath = drive[2] ? drive[2].replace(/\//g, '\\') : '';
270 return `${drive[1]}:\\${subPath}`;
271 }
272 return path.replace(/\//g, '\\');
273}
274exports.asWindowsPath = asWindowsPath;
275function asPosixPath(path) {
276 return path;
277}
278exports.asPosixPath = asPosixPath;
279function getSystemPath(path) {
280 if (process.platform.startsWith('win32')) {
281 return asWindowsPath(path);
282 }
283 else {
284 return asPosixPath(path);
285 }
286}
287exports.getSystemPath = getSystemPath;