Projekt

Obecné

Profil

Stáhnout (10.2 KB) Statistiky
| Větev: | Revize:
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+))?(\S*)$/;
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) === '/' || !!aPath.match(urlRegexp);
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 = 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 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 = 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 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 > aStr2) {
379
    return 1;
380
  }
381

    
382
  return -1;
383
}
384

    
385
/**
386
 * Comparator between two mappings with inflated source and name strings where
387
 * the generated positions are compared.
388
 */
389
function compareByGeneratedPositionsInflated(mappingA, mappingB) {
390
  var cmp = mappingA.generatedLine - mappingB.generatedLine;
391
  if (cmp !== 0) {
392
    return cmp;
393
  }
394

    
395
  cmp = mappingA.generatedColumn - mappingB.generatedColumn;
396
  if (cmp !== 0) {
397
    return cmp;
398
  }
399

    
400
  cmp = strcmp(mappingA.source, mappingB.source);
401
  if (cmp !== 0) {
402
    return cmp;
403
  }
404

    
405
  cmp = mappingA.originalLine - mappingB.originalLine;
406
  if (cmp !== 0) {
407
    return cmp;
408
  }
409

    
410
  cmp = mappingA.originalColumn - mappingB.originalColumn;
411
  if (cmp !== 0) {
412
    return cmp;
413
  }
414

    
415
  return strcmp(mappingA.name, mappingB.name);
416
}
417
exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated;
(10-10/10)