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 | */
|
---|
9 | Object.defineProperty(exports, "__esModule", { value: true });
|
---|
10 | exports.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;
|
---|
11 | const exception_1 = require("../exception");
|
---|
12 | class InvalidPathException extends exception_1.BaseException {
|
---|
13 | constructor(path) {
|
---|
14 | super(`Path ${JSON.stringify(path)} is invalid.`);
|
---|
15 | }
|
---|
16 | }
|
---|
17 | exports.InvalidPathException = InvalidPathException;
|
---|
18 | class PathMustBeAbsoluteException extends exception_1.BaseException {
|
---|
19 | constructor(path) {
|
---|
20 | super(`Path ${JSON.stringify(path)} must be absolute.`);
|
---|
21 | }
|
---|
22 | }
|
---|
23 | exports.PathMustBeAbsoluteException = PathMustBeAbsoluteException;
|
---|
24 | class PathCannotBeFragmentException extends exception_1.BaseException {
|
---|
25 | constructor(path) {
|
---|
26 | super(`Path ${JSON.stringify(path)} cannot be made a fragment.`);
|
---|
27 | }
|
---|
28 | }
|
---|
29 | exports.PathCannotBeFragmentException = PathCannotBeFragmentException;
|
---|
30 | /**
|
---|
31 | * The Separator for normalized path.
|
---|
32 | * @type {Path}
|
---|
33 | */
|
---|
34 | exports.NormalizedSep = '/';
|
---|
35 | /**
|
---|
36 | * The root of a normalized path.
|
---|
37 | * @type {Path}
|
---|
38 | */
|
---|
39 | exports.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 | */
|
---|
46 | function 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 | }
|
---|
53 | exports.split = split;
|
---|
54 | /**
|
---|
55 | *
|
---|
56 | */
|
---|
57 | function 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 | }
|
---|
67 | exports.extname = extname;
|
---|
68 | /**
|
---|
69 | * Return the basename of the path, as a Path. See path.basename
|
---|
70 | */
|
---|
71 | function 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 | }
|
---|
80 | exports.basename = basename;
|
---|
81 | /**
|
---|
82 | * Return the dirname of the path, as a Path. See path.dirname
|
---|
83 | */
|
---|
84 | function 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 | }
|
---|
92 | exports.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 | */
|
---|
97 | function 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 | }
|
---|
105 | exports.join = join;
|
---|
106 | /**
|
---|
107 | * Returns true if a path is absolute.
|
---|
108 | */
|
---|
109 | function isAbsolute(p) {
|
---|
110 | return p.startsWith(exports.NormalizedSep);
|
---|
111 | }
|
---|
112 | exports.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 | */
|
---|
117 | function 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 | }
|
---|
147 | exports.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 | */
|
---|
152 | function resolve(p1, p2) {
|
---|
153 | if (isAbsolute(p2)) {
|
---|
154 | return p2;
|
---|
155 | }
|
---|
156 | else {
|
---|
157 | return join(p1, p2);
|
---|
158 | }
|
---|
159 | }
|
---|
160 | exports.resolve = resolve;
|
---|
161 | function fragment(path) {
|
---|
162 | if (path.indexOf(exports.NormalizedSep) != -1) {
|
---|
163 | throw new PathCannotBeFragmentException(path);
|
---|
164 | }
|
---|
165 | return path;
|
---|
166 | }
|
---|
167 | exports.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 | */
|
---|
172 | let normalizedCache = new Map();
|
---|
173 | /**
|
---|
174 | * Reset the cache. This is only useful for testing.
|
---|
175 | * @private
|
---|
176 | */
|
---|
177 | function resetNormalizeCache() {
|
---|
178 | normalizedCache = new Map();
|
---|
179 | }
|
---|
180 | exports.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 | */
|
---|
195 | function 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 | }
|
---|
203 | exports.normalize = normalize;
|
---|
204 | /**
|
---|
205 | * The no cache version of the normalize() function. Used for benchmarking and testing.
|
---|
206 | */
|
---|
207 | function 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 | }
|
---|
261 | exports.noCacheNormalize = noCacheNormalize;
|
---|
262 | const path = (strings, ...values) => {
|
---|
263 | return normalize(String.raw(strings, ...values));
|
---|
264 | };
|
---|
265 | exports.path = path;
|
---|
266 | function 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 | }
|
---|
274 | exports.asWindowsPath = asWindowsPath;
|
---|
275 | function asPosixPath(path) {
|
---|
276 | return path;
|
---|
277 | }
|
---|
278 | exports.asPosixPath = asPosixPath;
|
---|
279 | function getSystemPath(path) {
|
---|
280 | if (process.platform.startsWith('win32')) {
|
---|
281 | return asWindowsPath(path);
|
---|
282 | }
|
---|
283 | else {
|
---|
284 | return asPosixPath(path);
|
---|
285 | }
|
---|
286 | }
|
---|
287 | exports.getSystemPath = getSystemPath;
|
---|