You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							418 lines
						
					
					
						
							10 KiB
						
					
					
				
			
		
		
	
	
							418 lines
						
					
					
						
							10 KiB
						
					
					
				/* -*- Mode: js; js-indent-level: 2; -*- */
 | 
						|
/*
 | 
						|
 * Copyright 2011 Mozilla Foundation and contributors
 | 
						|
 * Licensed under the New BSD license. See LICENSE or:
 | 
						|
 * http://opensource.org/licenses/BSD-3-Clause
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * This is a helper function for getting values from parameter/options
 | 
						|
 * objects.
 | 
						|
 *
 | 
						|
 * @param args The object we are extracting values from
 | 
						|
 * @param name The name of the property we are getting.
 | 
						|
 * @param defaultValue An optional value to return if the property is missing
 | 
						|
 * from the object. If this is not specified and the property is missing, an
 | 
						|
 * error will be thrown.
 | 
						|
 */
 | 
						|
function getArg(aArgs, aName, aDefaultValue) {
 | 
						|
  if (aName in aArgs) {
 | 
						|
    return aArgs[aName];
 | 
						|
  } else if (arguments.length === 3) {
 | 
						|
    return aDefaultValue;
 | 
						|
  } else {
 | 
						|
    throw new Error('"' + aName + '" is a required argument.');
 | 
						|
  }
 | 
						|
}
 | 
						|
exports.getArg = getArg;
 | 
						|
 | 
						|
var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.]*)(?::(\d+))?(\S*)$/;
 | 
						|
var dataUrlRegexp = /^data:.+\,.+$/;
 | 
						|
 | 
						|
function urlParse(aUrl) {
 | 
						|
  var match = aUrl.match(urlRegexp);
 | 
						|
  if (!match) {
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
  return {
 | 
						|
    scheme: match[1],
 | 
						|
    auth: match[2],
 | 
						|
    host: match[3],
 | 
						|
    port: match[4],
 | 
						|
    path: match[5]
 | 
						|
  };
 | 
						|
}
 | 
						|
exports.urlParse = urlParse;
 | 
						|
 | 
						|
function urlGenerate(aParsedUrl) {
 | 
						|
  var url = '';
 | 
						|
  if (aParsedUrl.scheme) {
 | 
						|
    url += aParsedUrl.scheme + ':';
 | 
						|
  }
 | 
						|
  url += '//';
 | 
						|
  if (aParsedUrl.auth) {
 | 
						|
    url += aParsedUrl.auth + '@';
 | 
						|
  }
 | 
						|
  if (aParsedUrl.host) {
 | 
						|
    url += aParsedUrl.host;
 | 
						|
  }
 | 
						|
  if (aParsedUrl.port) {
 | 
						|
    url += ":" + aParsedUrl.port
 | 
						|
  }
 | 
						|
  if (aParsedUrl.path) {
 | 
						|
    url += aParsedUrl.path;
 | 
						|
  }
 | 
						|
  return url;
 | 
						|
}
 | 
						|
exports.urlGenerate = urlGenerate;
 | 
						|
 | 
						|
/**
 | 
						|
 * Normalizes a path, or the path portion of a URL:
 | 
						|
 *
 | 
						|
 * - Replaces consecutive slashes with one slash.
 | 
						|
 * - Removes unnecessary '.' parts.
 | 
						|
 * - Removes unnecessary '<dir>/..' parts.
 | 
						|
 *
 | 
						|
 * Based on code in the Node.js 'path' core module.
 | 
						|
 *
 | 
						|
 * @param aPath The path or url to normalize.
 | 
						|
 */
 | 
						|
function normalize(aPath) {
 | 
						|
  var path = aPath;
 | 
						|
  var url = urlParse(aPath);
 | 
						|
  if (url) {
 | 
						|
    if (!url.path) {
 | 
						|
      return aPath;
 | 
						|
    }
 | 
						|
    path = url.path;
 | 
						|
  }
 | 
						|
  var isAbsolute = exports.isAbsolute(path);
 | 
						|
 | 
						|
  var parts = path.split(/\/+/);
 | 
						|
  for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
 | 
						|
    part = parts[i];
 | 
						|
    if (part === '.') {
 | 
						|
      parts.splice(i, 1);
 | 
						|
    } else if (part === '..') {
 | 
						|
      up++;
 | 
						|
    } else if (up > 0) {
 | 
						|
      if (part === '') {
 | 
						|
        // The first part is blank if the path is absolute. Trying to go
 | 
						|
        // above the root is a no-op. Therefore we can remove all '..' parts
 | 
						|
        // directly after the root.
 | 
						|
        parts.splice(i + 1, up);
 | 
						|
        up = 0;
 | 
						|
      } else {
 | 
						|
        parts.splice(i, 2);
 | 
						|
        up--;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  path = parts.join('/');
 | 
						|
 | 
						|
  if (path === '') {
 | 
						|
    path = isAbsolute ? '/' : '.';
 | 
						|
  }
 | 
						|
 | 
						|
  if (url) {
 | 
						|
    url.path = path;
 | 
						|
    return urlGenerate(url);
 | 
						|
  }
 | 
						|
  return path;
 | 
						|
}
 | 
						|
exports.normalize = normalize;
 | 
						|
 | 
						|
/**
 | 
						|
 * Joins two paths/URLs.
 | 
						|
 *
 | 
						|
 * @param aRoot The root path or URL.
 | 
						|
 * @param aPath The path or URL to be joined with the root.
 | 
						|
 *
 | 
						|
 * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a
 | 
						|
 *   scheme-relative URL: Then the scheme of aRoot, if any, is prepended
 | 
						|
 *   first.
 | 
						|
 * - Otherwise aPath is a path. If aRoot is a URL, then its path portion
 | 
						|
 *   is updated with the result and aRoot is returned. Otherwise the result
 | 
						|
 *   is returned.
 | 
						|
 *   - If aPath is absolute, the result is aPath.
 | 
						|
 *   - Otherwise the two paths are joined with a slash.
 | 
						|
 * - Joining for example 'http://' and 'www.example.com' is also supported.
 | 
						|
 */
 | 
						|
function join(aRoot, aPath) {
 | 
						|
  if (aRoot === "") {
 | 
						|
    aRoot = ".";
 | 
						|
  }
 | 
						|
  if (aPath === "") {
 | 
						|
    aPath = ".";
 | 
						|
  }
 | 
						|
  var aPathUrl = urlParse(aPath);
 | 
						|
  var aRootUrl = urlParse(aRoot);
 | 
						|
  if (aRootUrl) {
 | 
						|
    aRoot = aRootUrl.path || '/';
 | 
						|
  }
 | 
						|
 | 
						|
  // `join(foo, '//www.example.org')`
 | 
						|
  if (aPathUrl && !aPathUrl.scheme) {
 | 
						|
    if (aRootUrl) {
 | 
						|
      aPathUrl.scheme = aRootUrl.scheme;
 | 
						|
    }
 | 
						|
    return urlGenerate(aPathUrl);
 | 
						|
  }
 | 
						|
 | 
						|
  if (aPathUrl || aPath.match(dataUrlRegexp)) {
 | 
						|
    return aPath;
 | 
						|
  }
 | 
						|
 | 
						|
  // `join('http://', 'www.example.com')`
 | 
						|
  if (aRootUrl && !aRootUrl.host && !aRootUrl.path) {
 | 
						|
    aRootUrl.host = aPath;
 | 
						|
    return urlGenerate(aRootUrl);
 | 
						|
  }
 | 
						|
 | 
						|
  var joined = aPath.charAt(0) === '/'
 | 
						|
    ? aPath
 | 
						|
    : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath);
 | 
						|
 | 
						|
  if (aRootUrl) {
 | 
						|
    aRootUrl.path = joined;
 | 
						|
    return urlGenerate(aRootUrl);
 | 
						|
  }
 | 
						|
  return joined;
 | 
						|
}
 | 
						|
exports.join = join;
 | 
						|
 | 
						|
exports.isAbsolute = function (aPath) {
 | 
						|
  return aPath.charAt(0) === '/' || !!aPath.match(urlRegexp);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Make a path relative to a URL or another path.
 | 
						|
 *
 | 
						|
 * @param aRoot The root path or URL.
 | 
						|
 * @param aPath The path or URL to be made relative to aRoot.
 | 
						|
 */
 | 
						|
function relative(aRoot, aPath) {
 | 
						|
  if (aRoot === "") {
 | 
						|
    aRoot = ".";
 | 
						|
  }
 | 
						|
 | 
						|
  aRoot = aRoot.replace(/\/$/, '');
 | 
						|
 | 
						|
  // It is possible for the path to be above the root. In this case, simply
 | 
						|
  // checking whether the root is a prefix of the path won't work. Instead, we
 | 
						|
  // need to remove components from the root one by one, until either we find
 | 
						|
  // a prefix that fits, or we run out of components to remove.
 | 
						|
  var level = 0;
 | 
						|
  while (aPath.indexOf(aRoot + '/') !== 0) {
 | 
						|
    var index = aRoot.lastIndexOf("/");
 | 
						|
    if (index < 0) {
 | 
						|
      return aPath;
 | 
						|
    }
 | 
						|
 | 
						|
    // If the only part of the root that is left is the scheme (i.e. http://,
 | 
						|
    // file:///, etc.), one or more slashes (/), or simply nothing at all, we
 | 
						|
    // have exhausted all components, so the path is not relative to the root.
 | 
						|
    aRoot = aRoot.slice(0, index);
 | 
						|
    if (aRoot.match(/^([^\/]+:\/)?\/*$/)) {
 | 
						|
      return aPath;
 | 
						|
    }
 | 
						|
 | 
						|
    ++level;
 | 
						|
  }
 | 
						|
 | 
						|
  // Make sure we add a "../" for each component we removed from the root.
 | 
						|
  return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
 | 
						|
}
 | 
						|
exports.relative = relative;
 | 
						|
 | 
						|
var supportsNullProto = (function () {
 | 
						|
  var obj = Object.create(null);
 | 
						|
  return !('__proto__' in obj);
 | 
						|
}());
 | 
						|
 | 
						|
function identity (s) {
 | 
						|
  return s;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Because behavior goes wacky when you set `__proto__` on objects, we
 | 
						|
 * have to prefix all the strings in our set with an arbitrary character.
 | 
						|
 *
 | 
						|
 * See https://github.com/mozilla/source-map/pull/31 and
 | 
						|
 * https://github.com/mozilla/source-map/issues/30
 | 
						|
 *
 | 
						|
 * @param String aStr
 | 
						|
 */
 | 
						|
function toSetString(aStr) {
 | 
						|
  if (isProtoString(aStr)) {
 | 
						|
    return '$' + aStr;
 | 
						|
  }
 | 
						|
 | 
						|
  return aStr;
 | 
						|
}
 | 
						|
exports.toSetString = supportsNullProto ? identity : toSetString;
 | 
						|
 | 
						|
function fromSetString(aStr) {
 | 
						|
  if (isProtoString(aStr)) {
 | 
						|
    return aStr.slice(1);
 | 
						|
  }
 | 
						|
 | 
						|
  return aStr;
 | 
						|
}
 | 
						|
exports.fromSetString = supportsNullProto ? identity : fromSetString;
 | 
						|
 | 
						|
function isProtoString(s) {
 | 
						|
  if (!s) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  var length = s.length;
 | 
						|
 | 
						|
  if (length < 9 /* "__proto__".length */) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (s.charCodeAt(length - 1) !== 95  /* '_' */ ||
 | 
						|
      s.charCodeAt(length - 2) !== 95  /* '_' */ ||
 | 
						|
      s.charCodeAt(length - 3) !== 111 /* 'o' */ ||
 | 
						|
      s.charCodeAt(length - 4) !== 116 /* 't' */ ||
 | 
						|
      s.charCodeAt(length - 5) !== 111 /* 'o' */ ||
 | 
						|
      s.charCodeAt(length - 6) !== 114 /* 'r' */ ||
 | 
						|
      s.charCodeAt(length - 7) !== 112 /* 'p' */ ||
 | 
						|
      s.charCodeAt(length - 8) !== 95  /* '_' */ ||
 | 
						|
      s.charCodeAt(length - 9) !== 95  /* '_' */) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  for (var i = length - 10; i >= 0; i--) {
 | 
						|
    if (s.charCodeAt(i) !== 36 /* '$' */) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Comparator between two mappings where the original positions are compared.
 | 
						|
 *
 | 
						|
 * Optionally pass in `true` as `onlyCompareGenerated` to consider two
 | 
						|
 * mappings with the same original source/line/column, but different generated
 | 
						|
 * line and column the same. Useful when searching for a mapping with a
 | 
						|
 * stubbed out mapping.
 | 
						|
 */
 | 
						|
function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) {
 | 
						|
  var cmp = mappingA.source - mappingB.source;
 | 
						|
  if (cmp !== 0) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  cmp = mappingA.originalLine - mappingB.originalLine;
 | 
						|
  if (cmp !== 0) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  cmp = mappingA.originalColumn - mappingB.originalColumn;
 | 
						|
  if (cmp !== 0 || onlyCompareOriginal) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  cmp = mappingA.generatedColumn - mappingB.generatedColumn;
 | 
						|
  if (cmp !== 0) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  cmp = mappingA.generatedLine - mappingB.generatedLine;
 | 
						|
  if (cmp !== 0) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  return mappingA.name - mappingB.name;
 | 
						|
}
 | 
						|
exports.compareByOriginalPositions = compareByOriginalPositions;
 | 
						|
 | 
						|
/**
 | 
						|
 * Comparator between two mappings with deflated source and name indices where
 | 
						|
 * the generated positions are compared.
 | 
						|
 *
 | 
						|
 * Optionally pass in `true` as `onlyCompareGenerated` to consider two
 | 
						|
 * mappings with the same generated line and column, but different
 | 
						|
 * source/name/original line and column the same. Useful when searching for a
 | 
						|
 * mapping with a stubbed out mapping.
 | 
						|
 */
 | 
						|
function compareByGeneratedPositionsDeflated(mappingA, mappingB, onlyCompareGenerated) {
 | 
						|
  var cmp = mappingA.generatedLine - mappingB.generatedLine;
 | 
						|
  if (cmp !== 0) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  cmp = mappingA.generatedColumn - mappingB.generatedColumn;
 | 
						|
  if (cmp !== 0 || onlyCompareGenerated) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  cmp = mappingA.source - mappingB.source;
 | 
						|
  if (cmp !== 0) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  cmp = mappingA.originalLine - mappingB.originalLine;
 | 
						|
  if (cmp !== 0) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  cmp = mappingA.originalColumn - mappingB.originalColumn;
 | 
						|
  if (cmp !== 0) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  return mappingA.name - mappingB.name;
 | 
						|
}
 | 
						|
exports.compareByGeneratedPositionsDeflated = compareByGeneratedPositionsDeflated;
 | 
						|
 | 
						|
function strcmp(aStr1, aStr2) {
 | 
						|
  if (aStr1 === aStr2) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (aStr1 > aStr2) {
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  return -1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Comparator between two mappings with inflated source and name strings where
 | 
						|
 * the generated positions are compared.
 | 
						|
 */
 | 
						|
function compareByGeneratedPositionsInflated(mappingA, mappingB) {
 | 
						|
  var cmp = mappingA.generatedLine - mappingB.generatedLine;
 | 
						|
  if (cmp !== 0) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  cmp = mappingA.generatedColumn - mappingB.generatedColumn;
 | 
						|
  if (cmp !== 0) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  cmp = strcmp(mappingA.source, mappingB.source);
 | 
						|
  if (cmp !== 0) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  cmp = mappingA.originalLine - mappingB.originalLine;
 | 
						|
  if (cmp !== 0) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  cmp = mappingA.originalColumn - mappingB.originalColumn;
 | 
						|
  if (cmp !== 0) {
 | 
						|
    return cmp;
 | 
						|
  }
 | 
						|
 | 
						|
  return strcmp(mappingA.name, mappingB.name);
 | 
						|
}
 | 
						|
exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated;
 |