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

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

Update repo after prototype presentation

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