source: trip-planner-front/node_modules/source-map/lib/util.js@ 59329aa

Last change on this file since 59329aa was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 13.9 KB
Line 
1/* -*- Mode: js; js-indent-level: 2; -*- */
2/*
3 * Copyright 2011 Mozilla Foundation and contributors
4 * Licensed under the New BSD license. See LICENSE or:
5 * http://opensource.org/licenses/BSD-3-Clause
6 */
7
8/**
9 * This is a helper function for getting values from parameter/options
10 * objects.
11 *
12 * @param args The object we are extracting values from
13 * @param name The name of the property we are getting.
14 * @param defaultValue An optional value to return if the property is missing
15 * from the object. If this is not specified and the property is missing, an
16 * error will be thrown.
17 */
18function getArg(aArgs, aName, aDefaultValue) {
19 if (aName in aArgs) {
20 return aArgs[aName];
21 } else if (arguments.length === 3) {
22 return aDefaultValue;
23 }
24 throw new Error('"' + aName + '" is a required argument.');
25
26}
27exports.getArg = getArg;
28
29const urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/;
30const dataUrlRegexp = /^data:.+\,.+$/;
31
32function urlParse(aUrl) {
33 const match = aUrl.match(urlRegexp);
34 if (!match) {
35 return null;
36 }
37 return {
38 scheme: match[1],
39 auth: match[2],
40 host: match[3],
41 port: match[4],
42 path: match[5]
43 };
44}
45exports.urlParse = urlParse;
46
47function urlGenerate(aParsedUrl) {
48 let url = "";
49 if (aParsedUrl.scheme) {
50 url += aParsedUrl.scheme + ":";
51 }
52 url += "//";
53 if (aParsedUrl.auth) {
54 url += aParsedUrl.auth + "@";
55 }
56 if (aParsedUrl.host) {
57 url += aParsedUrl.host;
58 }
59 if (aParsedUrl.port) {
60 url += ":" + aParsedUrl.port;
61 }
62 if (aParsedUrl.path) {
63 url += aParsedUrl.path;
64 }
65 return url;
66}
67exports.urlGenerate = urlGenerate;
68
69const MAX_CACHED_INPUTS = 32;
70
71/**
72 * Takes some function `f(input) -> result` and returns a memoized version of
73 * `f`.
74 *
75 * We keep at most `MAX_CACHED_INPUTS` memoized results of `f` alive. The
76 * memoization is a dumb-simple, linear least-recently-used cache.
77 */
78function lruMemoize(f) {
79 const cache = [];
80
81 return function(input) {
82 for (let i = 0; i < cache.length; i++) {
83 if (cache[i].input === input) {
84 const temp = cache[0];
85 cache[0] = cache[i];
86 cache[i] = temp;
87 return cache[0].result;
88 }
89 }
90
91 const result = f(input);
92
93 cache.unshift({
94 input,
95 result,
96 });
97
98 if (cache.length > MAX_CACHED_INPUTS) {
99 cache.pop();
100 }
101
102 return result;
103 };
104}
105
106/**
107 * Normalizes a path, or the path portion of a URL:
108 *
109 * - Replaces consecutive slashes with one slash.
110 * - Removes unnecessary '.' parts.
111 * - Removes unnecessary '<dir>/..' parts.
112 *
113 * Based on code in the Node.js 'path' core module.
114 *
115 * @param aPath The path or url to normalize.
116 */
117const normalize = lruMemoize(function normalize(aPath) {
118 let path = aPath;
119 const url = urlParse(aPath);
120 if (url) {
121 if (!url.path) {
122 return aPath;
123 }
124 path = url.path;
125 }
126 const isAbsolute = exports.isAbsolute(path);
127
128 // Split the path into parts between `/` characters. This is much faster than
129 // using `.split(/\/+/g)`.
130 const parts = [];
131 let start = 0;
132 let i = 0;
133 while (true) {
134 start = i;
135 i = path.indexOf("/", start);
136 if (i === -1) {
137 parts.push(path.slice(start));
138 break;
139 } else {
140 parts.push(path.slice(start, i));
141 while (i < path.length && path[i] === "/") {
142 i++;
143 }
144 }
145 }
146
147 let up = 0;
148 for (i = parts.length - 1; i >= 0; i--) {
149 const part = parts[i];
150 if (part === ".") {
151 parts.splice(i, 1);
152 } else if (part === "..") {
153 up++;
154 } else if (up > 0) {
155 if (part === "") {
156 // The first part is blank if the path is absolute. Trying to go
157 // above the root is a no-op. Therefore we can remove all '..' parts
158 // directly after the root.
159 parts.splice(i + 1, up);
160 up = 0;
161 } else {
162 parts.splice(i, 2);
163 up--;
164 }
165 }
166 }
167 path = parts.join("/");
168
169 if (path === "") {
170 path = isAbsolute ? "/" : ".";
171 }
172
173 if (url) {
174 url.path = path;
175 return urlGenerate(url);
176 }
177 return path;
178});
179exports.normalize = normalize;
180
181/**
182 * Joins two paths/URLs.
183 *
184 * @param aRoot The root path or URL.
185 * @param aPath The path or URL to be joined with the root.
186 *
187 * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a
188 * scheme-relative URL: Then the scheme of aRoot, if any, is prepended
189 * first.
190 * - Otherwise aPath is a path. If aRoot is a URL, then its path portion
191 * is updated with the result and aRoot is returned. Otherwise the result
192 * is returned.
193 * - If aPath is absolute, the result is aPath.
194 * - Otherwise the two paths are joined with a slash.
195 * - Joining for example 'http://' and 'www.example.com' is also supported.
196 */
197function join(aRoot, aPath) {
198 if (aRoot === "") {
199 aRoot = ".";
200 }
201 if (aPath === "") {
202 aPath = ".";
203 }
204 const aPathUrl = urlParse(aPath);
205 const aRootUrl = urlParse(aRoot);
206 if (aRootUrl) {
207 aRoot = aRootUrl.path || "/";
208 }
209
210 // `join(foo, '//www.example.org')`
211 if (aPathUrl && !aPathUrl.scheme) {
212 if (aRootUrl) {
213 aPathUrl.scheme = aRootUrl.scheme;
214 }
215 return urlGenerate(aPathUrl);
216 }
217
218 if (aPathUrl || aPath.match(dataUrlRegexp)) {
219 return aPath;
220 }
221
222 // `join('http://', 'www.example.com')`
223 if (aRootUrl && !aRootUrl.host && !aRootUrl.path) {
224 aRootUrl.host = aPath;
225 return urlGenerate(aRootUrl);
226 }
227
228 const joined = aPath.charAt(0) === "/"
229 ? aPath
230 : normalize(aRoot.replace(/\/+$/, "") + "/" + aPath);
231
232 if (aRootUrl) {
233 aRootUrl.path = joined;
234 return urlGenerate(aRootUrl);
235 }
236 return joined;
237}
238exports.join = join;
239
240exports.isAbsolute = function(aPath) {
241 return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
242};
243
244/**
245 * Make a path relative to a URL or another path.
246 *
247 * @param aRoot The root path or URL.
248 * @param aPath The path or URL to be made relative to aRoot.
249 */
250function relative(aRoot, aPath) {
251 if (aRoot === "") {
252 aRoot = ".";
253 }
254
255 aRoot = aRoot.replace(/\/$/, "");
256
257 // It is possible for the path to be above the root. In this case, simply
258 // checking whether the root is a prefix of the path won't work. Instead, we
259 // need to remove components from the root one by one, until either we find
260 // a prefix that fits, or we run out of components to remove.
261 let level = 0;
262 while (aPath.indexOf(aRoot + "/") !== 0) {
263 const index = aRoot.lastIndexOf("/");
264 if (index < 0) {
265 return aPath;
266 }
267
268 // If the only part of the root that is left is the scheme (i.e. http://,
269 // file:///, etc.), one or more slashes (/), or simply nothing at all, we
270 // have exhausted all components, so the path is not relative to the root.
271 aRoot = aRoot.slice(0, index);
272 if (aRoot.match(/^([^\/]+:\/)?\/*$/)) {
273 return aPath;
274 }
275
276 ++level;
277 }
278
279 // Make sure we add a "../" for each component we removed from the root.
280 return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
281}
282exports.relative = relative;
283
284const supportsNullProto = (function() {
285 const obj = Object.create(null);
286 return !("__proto__" in obj);
287}());
288
289function identity(s) {
290 return s;
291}
292
293/**
294 * Because behavior goes wacky when you set `__proto__` on objects, we
295 * have to prefix all the strings in our set with an arbitrary character.
296 *
297 * See https://github.com/mozilla/source-map/pull/31 and
298 * https://github.com/mozilla/source-map/issues/30
299 *
300 * @param String aStr
301 */
302function toSetString(aStr) {
303 if (isProtoString(aStr)) {
304 return "$" + aStr;
305 }
306
307 return aStr;
308}
309exports.toSetString = supportsNullProto ? identity : toSetString;
310
311function fromSetString(aStr) {
312 if (isProtoString(aStr)) {
313 return aStr.slice(1);
314 }
315
316 return aStr;
317}
318exports.fromSetString = supportsNullProto ? identity : fromSetString;
319
320function isProtoString(s) {
321 if (!s) {
322 return false;
323 }
324
325 const length = s.length;
326
327 if (length < 9 /* "__proto__".length */) {
328 return false;
329 }
330
331 /* eslint-disable no-multi-spaces */
332 if (s.charCodeAt(length - 1) !== 95 /* '_' */ ||
333 s.charCodeAt(length - 2) !== 95 /* '_' */ ||
334 s.charCodeAt(length - 3) !== 111 /* 'o' */ ||
335 s.charCodeAt(length - 4) !== 116 /* 't' */ ||
336 s.charCodeAt(length - 5) !== 111 /* 'o' */ ||
337 s.charCodeAt(length - 6) !== 114 /* 'r' */ ||
338 s.charCodeAt(length - 7) !== 112 /* 'p' */ ||
339 s.charCodeAt(length - 8) !== 95 /* '_' */ ||
340 s.charCodeAt(length - 9) !== 95 /* '_' */) {
341 return false;
342 }
343 /* eslint-enable no-multi-spaces */
344
345 for (let i = length - 10; i >= 0; i--) {
346 if (s.charCodeAt(i) !== 36 /* '$' */) {
347 return false;
348 }
349 }
350
351 return true;
352}
353
354/**
355 * Comparator between two mappings where the original positions are compared.
356 *
357 * Optionally pass in `true` as `onlyCompareGenerated` to consider two
358 * mappings with the same original source/line/column, but different generated
359 * line and column the same. Useful when searching for a mapping with a
360 * stubbed out mapping.
361 */
362function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) {
363 let cmp = strcmp(mappingA.source, mappingB.source);
364 if (cmp !== 0) {
365 return cmp;
366 }
367
368 cmp = mappingA.originalLine - mappingB.originalLine;
369 if (cmp !== 0) {
370 return cmp;
371 }
372
373 cmp = mappingA.originalColumn - mappingB.originalColumn;
374 if (cmp !== 0 || onlyCompareOriginal) {
375 return cmp;
376 }
377
378 cmp = mappingA.generatedColumn - mappingB.generatedColumn;
379 if (cmp !== 0) {
380 return cmp;
381 }
382
383 cmp = mappingA.generatedLine - mappingB.generatedLine;
384 if (cmp !== 0) {
385 return cmp;
386 }
387
388 return strcmp(mappingA.name, mappingB.name);
389}
390exports.compareByOriginalPositions = compareByOriginalPositions;
391
392/**
393 * Comparator between two mappings with deflated source and name indices where
394 * the generated positions are compared.
395 *
396 * Optionally pass in `true` as `onlyCompareGenerated` to consider two
397 * mappings with the same generated line and column, but different
398 * source/name/original line and column the same. Useful when searching for a
399 * mapping with a stubbed out mapping.
400 */
401function compareByGeneratedPositionsDeflated(mappingA, mappingB, onlyCompareGenerated) {
402 let cmp = mappingA.generatedLine - mappingB.generatedLine;
403 if (cmp !== 0) {
404 return cmp;
405 }
406
407 cmp = mappingA.generatedColumn - mappingB.generatedColumn;
408 if (cmp !== 0 || onlyCompareGenerated) {
409 return cmp;
410 }
411
412 cmp = strcmp(mappingA.source, mappingB.source);
413 if (cmp !== 0) {
414 return cmp;
415 }
416
417 cmp = mappingA.originalLine - mappingB.originalLine;
418 if (cmp !== 0) {
419 return cmp;
420 }
421
422 cmp = mappingA.originalColumn - mappingB.originalColumn;
423 if (cmp !== 0) {
424 return cmp;
425 }
426
427 return strcmp(mappingA.name, mappingB.name);
428}
429exports.compareByGeneratedPositionsDeflated = compareByGeneratedPositionsDeflated;
430
431function strcmp(aStr1, aStr2) {
432 if (aStr1 === aStr2) {
433 return 0;
434 }
435
436 if (aStr1 === null) {
437 return 1; // aStr2 !== null
438 }
439
440 if (aStr2 === null) {
441 return -1; // aStr1 !== null
442 }
443
444 if (aStr1 > aStr2) {
445 return 1;
446 }
447
448 return -1;
449}
450
451/**
452 * Comparator between two mappings with inflated source and name strings where
453 * the generated positions are compared.
454 */
455function compareByGeneratedPositionsInflated(mappingA, mappingB) {
456 let cmp = mappingA.generatedLine - mappingB.generatedLine;
457 if (cmp !== 0) {
458 return cmp;
459 }
460
461 cmp = mappingA.generatedColumn - mappingB.generatedColumn;
462 if (cmp !== 0) {
463 return cmp;
464 }
465
466 cmp = strcmp(mappingA.source, mappingB.source);
467 if (cmp !== 0) {
468 return cmp;
469 }
470
471 cmp = mappingA.originalLine - mappingB.originalLine;
472 if (cmp !== 0) {
473 return cmp;
474 }
475
476 cmp = mappingA.originalColumn - mappingB.originalColumn;
477 if (cmp !== 0) {
478 return cmp;
479 }
480
481 return strcmp(mappingA.name, mappingB.name);
482}
483exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated;
484
485/**
486 * Strip any JSON XSSI avoidance prefix from the string (as documented
487 * in the source maps specification), and then parse the string as
488 * JSON.
489 */
490function parseSourceMapInput(str) {
491 return JSON.parse(str.replace(/^\)]}'[^\n]*\n/, ""));
492}
493exports.parseSourceMapInput = parseSourceMapInput;
494
495/**
496 * Compute the URL of a source given the the source root, the source's
497 * URL, and the source map's URL.
498 */
499function computeSourceURL(sourceRoot, sourceURL, sourceMapURL) {
500 sourceURL = sourceURL || "";
501
502 if (sourceRoot) {
503 // This follows what Chrome does.
504 if (sourceRoot[sourceRoot.length - 1] !== "/" && sourceURL[0] !== "/") {
505 sourceRoot += "/";
506 }
507 // The spec says:
508 // Line 4: An optional source root, useful for relocating source
509 // files on a server or removing repeated values in the
510 // “sources” entry. This value is prepended to the individual
511 // entries in the “source” field.
512 sourceURL = sourceRoot + sourceURL;
513 }
514
515 // Historically, SourceMapConsumer did not take the sourceMapURL as
516 // a parameter. This mode is still somewhat supported, which is why
517 // this code block is conditional. However, it's preferable to pass
518 // the source map URL to SourceMapConsumer, so that this function
519 // can implement the source URL resolution algorithm as outlined in
520 // the spec. This block is basically the equivalent of:
521 // new URL(sourceURL, sourceMapURL).toString()
522 // ... except it avoids using URL, which wasn't available in the
523 // older releases of node still supported by this library.
524 //
525 // The spec says:
526 // If the sources are not absolute URLs after prepending of the
527 // “sourceRoot”, the sources are resolved relative to the
528 // SourceMap (like resolving script src in a html document).
529 if (sourceMapURL) {
530 const parsed = urlParse(sourceMapURL);
531 if (!parsed) {
532 throw new Error("sourceMapURL could not be parsed");
533 }
534 if (parsed.path) {
535 // Strip the last path component, but keep the "/".
536 const index = parsed.path.lastIndexOf("/");
537 if (index >= 0) {
538 parsed.path = parsed.path.substring(0, index + 1);
539 }
540 }
541 sourceURL = join(urlGenerate(parsed), sourceURL);
542 }
543
544 return normalize(sourceURL);
545}
546exports.computeSourceURL = computeSourceURL;
Note: See TracBrowser for help on using the repository browser.