.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / source-map / lib / util.js
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  */
18 function 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 }
27 exports.getArg = getArg;
28
29 var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/;
30 var dataUrlRegexp = /^data:.+\,.+$/;
31
32 function 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 }
45 exports.urlParse = urlParse;
46
47 function 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 }
67 exports.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  */
80 function 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 }
123 exports.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  */
141 function 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 }
182 exports.join = join;
183
184 exports.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  */
194 function 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 }
226 exports.relative = relative;
227
228 var supportsNullProto = (function () {
229   var obj = Object.create(null);
230   return !('__proto__' in obj);
231 }());
232
233 function 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  */
246 function toSetString(aStr) {
247   if (isProtoString(aStr)) {
248     return '$' + aStr;
249   }
250
251   return aStr;
252 }
253 exports.toSetString = supportsNullProto ? identity : toSetString;
254
255 function fromSetString(aStr) {
256   if (isProtoString(aStr)) {
257     return aStr.slice(1);
258   }
259
260   return aStr;
261 }
262 exports.fromSetString = supportsNullProto ? identity : fromSetString;
263
264 function 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  */
304 function 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 }
332 exports.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  */
343 function 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 }
371 exports.compareByGeneratedPositionsDeflated = compareByGeneratedPositionsDeflated;
372
373 function 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  */
397 function 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 }
425 exports.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  */
432 function parseSourceMapInput(str) {
433   return JSON.parse(str.replace(/^\)]}'[^\n]*\n/, ''));
434 }
435 exports.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  */
441 function 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 }
488 exports.computeSourceURL = computeSourceURL;