source: imaps-frontend/node_modules/source-map-js/lib/util.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

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