1 /* -*- Mode: js; js-indent-level: 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
7 if (typeof define !== 'function') {
8 var define = require('amdefine')(module, require);
10 define(function (require, exports, module) {
13 * This is a helper function for getting values from parameter/options
16 * @param args The object we are extracting values from
17 * @param name The name of the property we are getting.
18 * @param defaultValue An optional value to return if the property is missing
19 * from the object. If this is not specified and the property is missing, an
20 * error will be thrown.
22 function getArg(aArgs, aName, aDefaultValue) {
25 } else if (arguments.length === 3) {
28 throw new Error('"' + aName + '" is a required argument.');
31 exports.getArg = getArg;
33 var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.]*)(?::(\d+))?(\S*)$/;
34 var dataUrlRegexp = /^data:.+\,.+$/;
36 function urlParse(aUrl) {
37 var match = aUrl.match(urlRegexp);
49 exports.urlParse = urlParse;
51 function urlGenerate(aParsedUrl) {
53 if (aParsedUrl.scheme) {
54 url += aParsedUrl.scheme + ':';
57 if (aParsedUrl.auth) {
58 url += aParsedUrl.auth + '@';
60 if (aParsedUrl.host) {
61 url += aParsedUrl.host;
63 if (aParsedUrl.port) {
64 url += ":" + aParsedUrl.port
66 if (aParsedUrl.path) {
67 url += aParsedUrl.path;
71 exports.urlGenerate = urlGenerate;
74 * Normalizes a path, or the path portion of a URL:
76 * - Replaces consequtive slashes with one slash.
77 * - Removes unnecessary '.' parts.
78 * - Removes unnecessary '<dir>/..' parts.
80 * Based on code in the Node.js 'path' core module.
82 * @param aPath The path or url to normalize.
84 function normalize(aPath) {
86 var url = urlParse(aPath);
93 var isAbsolute = (path.charAt(0) === '/');
95 var parts = path.split(/\/+/);
96 for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
100 } else if (part === '..') {
104 // The first part is blank if the path is absolute. Trying to go
105 // above the root is a no-op. Therefore we can remove all '..' parts
106 // directly after the root.
107 parts.splice(i + 1, up);
115 path = parts.join('/');
118 path = isAbsolute ? '/' : '.';
123 return urlGenerate(url);
127 exports.normalize = normalize;
130 * Joins two paths/URLs.
132 * @param aRoot The root path or URL.
133 * @param aPath The path or URL to be joined with the root.
135 * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a
136 * scheme-relative URL: Then the scheme of aRoot, if any, is prepended
138 * - Otherwise aPath is a path. If aRoot is a URL, then its path portion
139 * is updated with the result and aRoot is returned. Otherwise the result
141 * - If aPath is absolute, the result is aPath.
142 * - Otherwise the two paths are joined with a slash.
143 * - Joining for example 'http://' and 'www.example.com' is also supported.
145 function join(aRoot, aPath) {
152 var aPathUrl = urlParse(aPath);
153 var aRootUrl = urlParse(aRoot);
155 aRoot = aRootUrl.path || '/';
158 // `join(foo, '//www.example.org')`
159 if (aPathUrl && !aPathUrl.scheme) {
161 aPathUrl.scheme = aRootUrl.scheme;
163 return urlGenerate(aPathUrl);
166 if (aPathUrl || aPath.match(dataUrlRegexp)) {
170 // `join('http://', 'www.example.com')`
171 if (aRootUrl && !aRootUrl.host && !aRootUrl.path) {
172 aRootUrl.host = aPath;
173 return urlGenerate(aRootUrl);
176 var joined = aPath.charAt(0) === '/'
178 : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath);
181 aRootUrl.path = joined;
182 return urlGenerate(aRootUrl);
189 * Make a path relative to a URL or another path.
191 * @param aRoot The root path or URL.
192 * @param aPath The path or URL to be made relative to aRoot.
194 function relative(aRoot, aPath) {
199 aRoot = aRoot.replace(/\/$/, '');
201 // XXX: It is possible to remove this block, and the tests still pass!
202 var url = urlParse(aRoot);
203 if (aPath.charAt(0) == "/" && url && url.path == "/") {
204 return aPath.slice(1);
207 return aPath.indexOf(aRoot + '/') === 0
208 ? aPath.substr(aRoot.length + 1)
211 exports.relative = relative;
214 * Because behavior goes wacky when you set `__proto__` on objects, we
215 * have to prefix all the strings in our set with an arbitrary character.
217 * See https://github.com/mozilla/source-map/pull/31 and
218 * https://github.com/mozilla/source-map/issues/30
222 function toSetString(aStr) {
225 exports.toSetString = toSetString;
227 function fromSetString(aStr) {
228 return aStr.substr(1);
230 exports.fromSetString = fromSetString;
232 function strcmp(aStr1, aStr2) {
233 var s1 = aStr1 || "";
234 var s2 = aStr2 || "";
235 return (s1 > s2) - (s1 < s2);
239 * Comparator between two mappings where the original positions are compared.
241 * Optionally pass in `true` as `onlyCompareGenerated` to consider two
242 * mappings with the same original source/line/column, but different generated
243 * line and column the same. Useful when searching for a mapping with a
244 * stubbed out mapping.
246 function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) {
249 cmp = strcmp(mappingA.source, mappingB.source);
254 cmp = mappingA.originalLine - mappingB.originalLine;
259 cmp = mappingA.originalColumn - mappingB.originalColumn;
260 if (cmp || onlyCompareOriginal) {
264 cmp = strcmp(mappingA.name, mappingB.name);
269 cmp = mappingA.generatedLine - mappingB.generatedLine;
274 return mappingA.generatedColumn - mappingB.generatedColumn;
276 exports.compareByOriginalPositions = compareByOriginalPositions;
279 * Comparator between two mappings where the generated positions are
282 * Optionally pass in `true` as `onlyCompareGenerated` to consider two
283 * mappings with the same generated line and column, but different
284 * source/name/original line and column the same. Useful when searching for a
285 * mapping with a stubbed out mapping.
287 function compareByGeneratedPositions(mappingA, mappingB, onlyCompareGenerated) {
290 cmp = mappingA.generatedLine - mappingB.generatedLine;
295 cmp = mappingA.generatedColumn - mappingB.generatedColumn;
296 if (cmp || onlyCompareGenerated) {
300 cmp = strcmp(mappingA.source, mappingB.source);
305 cmp = mappingA.originalLine - mappingB.originalLine;
310 cmp = mappingA.originalColumn - mappingB.originalColumn;
315 return strcmp(mappingA.name, mappingB.name);
317 exports.compareByGeneratedPositions = compareByGeneratedPositions;