[6a3a178] | 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;
|
---|