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
;