[Pkg-javascript-commits] [node-source-map] 01/05: Imported Upstream version 0.1.40

Leo Iannacone l3on-guest at moszumanska.debian.org
Sun Oct 12 12:18:42 UTC 2014


This is an automated email from the git hooks/post-receive script.

l3on-guest pushed a commit to branch master
in repository node-source-map.

commit a2b492d735fd20574aabb613688e74bef7050ab8
Author: Leo Iannacone <l3on at ubuntu.com>
Date:   Sun Oct 12 12:27:52 2014 +0200

    Imported Upstream version 0.1.40
---
 CHANGELOG.md                                 |  36 ++++++++
 README.md                                    |   7 +-
 lib/source-map/base64-vlq.js                 |  10 +--
 lib/source-map/source-map-consumer.js        |  39 ++++----
 lib/source-map/source-map-generator.js       |  67 +++++++-------
 lib/source-map/source-node.js                |  24 +++--
 lib/source-map/util.js                       |  45 +++++++---
 package.json                                 |   8 +-
 test/source-map/test-base64-vlq.js           |   5 +-
 test/source-map/test-source-map-consumer.js  |  70 +++++++++++++--
 test/source-map/test-source-map-generator.js | 127 +++++++++++++++++++++++++--
 test/source-map/test-source-node.js          | 125 ++++++++++++++++++++++++++
 test/source-map/test-util.js                 |  89 +++++++++++++++++++
 test/source-map/util.js                      |  15 ++++
 14 files changed, 566 insertions(+), 101 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 240d54a..518bed4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,41 @@
 # Change Log
 
+## 0.1.40
+
+* Performance improvements for parsing source maps in SourceMapConsumer.
+
+## 0.1.39
+
+* Fix a bug where setting a source's contents to null before any source content
+  had been set before threw a TypeError. See issue #131.
+
+## 0.1.38
+
+* Fix a bug where finding relative paths from an empty path were creating
+  absolute paths. See issue #129.
+
+## 0.1.37
+
+* Fix a bug where if the source root was an empty string, relative source paths
+  would turn into absolute source paths. Issue #124.
+
+## 0.1.36
+
+* Allow the `names` mapping property to be an empty string. Issue #121.
+
+## 0.1.35
+
+* A third optional parameter was added to `SourceNode.fromStringWithSourceMap`
+  to specify a path that relative sources in the second parameter should be
+  relative to. Issue #105.
+
+* If no file property is given to a `SourceMapGenerator`, then the resulting
+  source map will no longer have a `null` file property. The property will
+  simply not exist. Issue #104.
+
+* Fixed a bug where consecutive newlines were ignored in `SourceNode`s.
+  Issue #116.
+
 ## 0.1.34
 
 * Make `SourceNode` work with windows style ("\r\n") newlines. Issue #103.
diff --git a/README.md b/README.md
index b00e970..1a1c7d8 100644
--- a/README.md
+++ b/README.md
@@ -332,7 +332,7 @@ use before outputting the generated JS and source map.
 
 * `name`: Optional. The original identifier.
 
-#### SourceNode.fromStringWithSourceMap(code, sourceMapConsumer)
+#### SourceNode.fromStringWithSourceMap(code, sourceMapConsumer[, relativePath])
 
 Creates a SourceNode from generated code and a SourceMapConsumer.
 
@@ -340,6 +340,9 @@ Creates a SourceNode from generated code and a SourceMapConsumer.
 
 * `sourceMapConsumer` The SourceMap for the generated code
 
+* `relativePath` The optional path that relative sources in `sourceMapConsumer`
+  should be relative to.
+
 #### SourceNode.prototype.add(chunk)
 
 Add a chunk of generated JS to this source node.
@@ -399,7 +402,7 @@ for trimming whitespace from the end of a source node, etc.
 Return the string representation of this source node. Walks over the tree and
 concatenates all the various snippets together to one string.
 
-### SourceNode.prototype.toStringWithSourceMap([startOfSourceMap])
+#### SourceNode.prototype.toStringWithSourceMap([startOfSourceMap])
 
 Returns the string representation of this tree of source nodes, plus a
 SourceMapGenerator which contains all the mappings between the generated and
diff --git a/lib/source-map/base64-vlq.js b/lib/source-map/base64-vlq.js
index 1b67bb3..b4ff136 100644
--- a/lib/source-map/base64-vlq.js
+++ b/lib/source-map/base64-vlq.js
@@ -115,9 +115,9 @@ define(function (require, exports, module) {
 
   /**
    * Decodes the next base 64 VLQ value from the given string and returns the
-   * value and the rest of the string.
+   * value and the rest of the string via the out parameter.
    */
-  exports.decode = function base64VLQ_decode(aStr) {
+  exports.decode = function base64VLQ_decode(aStr, aOutParam) {
     var i = 0;
     var strLen = aStr.length;
     var result = 0;
@@ -135,10 +135,8 @@ define(function (require, exports, module) {
       shift += VLQ_BASE_SHIFT;
     } while (continuation);
 
-    return {
-      value: fromVLQSigned(result),
-      rest: aStr.slice(i)
-    };
+    aOutParam.value = fromVLQSigned(result);
+    aOutParam.rest = aStr.slice(i);
   };
 
 });
diff --git a/lib/source-map/source-map-consumer.js b/lib/source-map/source-map-consumer.js
index 5214d5e..ea643bf 100644
--- a/lib/source-map/source-map-consumer.js
+++ b/lib/source-map/source-map-consumer.js
@@ -116,7 +116,7 @@ define(function (require, exports, module) {
   Object.defineProperty(SourceMapConsumer.prototype, 'sources', {
     get: function () {
       return this._sources.toArray().map(function (s) {
-        return this.sourceRoot ? util.join(this.sourceRoot, s) : s;
+        return this.sourceRoot != null ? util.join(this.sourceRoot, s) : s;
       }, this);
     }
   });
@@ -177,6 +177,12 @@ define(function (require, exports, module) {
     }
   });
 
+  SourceMapConsumer.prototype._nextCharIsMappingSeparator =
+    function SourceMapConsumer_nextCharIsMappingSeparator(aStr) {
+      var c = aStr.charAt(0);
+      return c === ";" || c === ",";
+    };
+
   /**
    * Parse the mappings in a string in to a data structure which we can easily
    * query (the ordered arrays in the `this.__generatedMappings` and
@@ -190,10 +196,9 @@ define(function (require, exports, module) {
       var previousOriginalColumn = 0;
       var previousSource = 0;
       var previousName = 0;
-      var mappingSeparator = /^[,;]/;
       var str = aStr;
+      var temp = {};
       var mapping;
-      var temp;
 
       while (str.length > 0) {
         if (str.charAt(0) === ';') {
@@ -209,41 +214,41 @@ define(function (require, exports, module) {
           mapping.generatedLine = generatedLine;
 
           // Generated column.
-          temp = base64VLQ.decode(str);
+          base64VLQ.decode(str, temp);
           mapping.generatedColumn = previousGeneratedColumn + temp.value;
           previousGeneratedColumn = mapping.generatedColumn;
           str = temp.rest;
 
-          if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
+          if (str.length > 0 && !this._nextCharIsMappingSeparator(str)) {
             // Original source.
-            temp = base64VLQ.decode(str);
+            base64VLQ.decode(str, temp);
             mapping.source = this._sources.at(previousSource + temp.value);
             previousSource += temp.value;
             str = temp.rest;
-            if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
+            if (str.length === 0 || this._nextCharIsMappingSeparator(str)) {
               throw new Error('Found a source, but no line and column');
             }
 
             // Original line.
-            temp = base64VLQ.decode(str);
+            base64VLQ.decode(str, temp);
             mapping.originalLine = previousOriginalLine + temp.value;
             previousOriginalLine = mapping.originalLine;
             // Lines are stored 0-based
             mapping.originalLine += 1;
             str = temp.rest;
-            if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
+            if (str.length === 0 || this._nextCharIsMappingSeparator(str)) {
               throw new Error('Found a source and line, but no column');
             }
 
             // Original column.
-            temp = base64VLQ.decode(str);
+            base64VLQ.decode(str, temp);
             mapping.originalColumn = previousOriginalColumn + temp.value;
             previousOriginalColumn = mapping.originalColumn;
             str = temp.rest;
 
-            if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
+            if (str.length > 0 && !this._nextCharIsMappingSeparator(str)) {
               // Original name.
-              temp = base64VLQ.decode(str);
+              base64VLQ.decode(str, temp);
               mapping.name = this._names.at(previousName + temp.value);
               previousName += temp.value;
               str = temp.rest;
@@ -315,7 +320,7 @@ define(function (require, exports, module) {
 
       if (mapping && mapping.generatedLine === needle.generatedLine) {
         var source = util.getArg(mapping, 'source', null);
-        if (source && this.sourceRoot) {
+        if (source != null && this.sourceRoot != null) {
           source = util.join(this.sourceRoot, source);
         }
         return {
@@ -345,7 +350,7 @@ define(function (require, exports, module) {
         return null;
       }
 
-      if (this.sourceRoot) {
+      if (this.sourceRoot != null) {
         aSource = util.relative(this.sourceRoot, aSource);
       }
 
@@ -354,7 +359,7 @@ define(function (require, exports, module) {
       }
 
       var url;
-      if (this.sourceRoot
+      if (this.sourceRoot != null
           && (url = util.urlParse(this.sourceRoot))) {
         // XXX: file:// URIs and absolute paths lead to unexpected behavior for
         // many users. We can help them out when they expect file:// URIs to
@@ -397,7 +402,7 @@ define(function (require, exports, module) {
         originalColumn: util.getArg(aArgs, 'column')
       };
 
-      if (this.sourceRoot) {
+      if (this.sourceRoot != null) {
         needle.source = util.relative(this.sourceRoot, needle.source);
       }
 
@@ -459,7 +464,7 @@ define(function (require, exports, module) {
       var sourceRoot = this.sourceRoot;
       mappings.map(function (mapping) {
         var source = mapping.source;
-        if (source && sourceRoot) {
+        if (source != null && sourceRoot != null) {
           source = util.join(sourceRoot, source);
         }
         return {
diff --git a/lib/source-map/source-map-generator.js b/lib/source-map/source-map-generator.js
index fb6d6c3..5387fa1 100644
--- a/lib/source-map/source-map-generator.js
+++ b/lib/source-map/source-map-generator.js
@@ -55,9 +55,9 @@ define(function (require, exports, module) {
           }
         };
 
-        if (mapping.source) {
+        if (mapping.source != null) {
           newMapping.source = mapping.source;
-          if (sourceRoot) {
+          if (sourceRoot != null) {
             newMapping.source = util.relative(sourceRoot, newMapping.source);
           }
 
@@ -66,7 +66,7 @@ define(function (require, exports, module) {
             column: mapping.originalColumn
           };
 
-          if (mapping.name) {
+          if (mapping.name != null) {
             newMapping.name = mapping.name;
           }
         }
@@ -75,7 +75,7 @@ define(function (require, exports, module) {
       });
       aSourceMapConsumer.sources.forEach(function (sourceFile) {
         var content = aSourceMapConsumer.sourceContentFor(sourceFile);
-        if (content) {
+        if (content != null) {
           generator.setSourceContent(sourceFile, content);
         }
       });
@@ -101,11 +101,11 @@ define(function (require, exports, module) {
 
       this._validateMapping(generated, original, source, name);
 
-      if (source && !this._sources.has(source)) {
+      if (source != null && !this._sources.has(source)) {
         this._sources.add(source);
       }
 
-      if (name && !this._names.has(name)) {
+      if (name != null && !this._names.has(name)) {
         this._names.add(name);
       }
 
@@ -125,18 +125,18 @@ define(function (require, exports, module) {
   SourceMapGenerator.prototype.setSourceContent =
     function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) {
       var source = aSourceFile;
-      if (this._sourceRoot) {
+      if (this._sourceRoot != null) {
         source = util.relative(this._sourceRoot, source);
       }
 
-      if (aSourceContent !== null) {
+      if (aSourceContent != null) {
         // Add the source content to the _sourcesContents map.
         // Create a new _sourcesContents map if the property is null.
         if (!this._sourcesContents) {
           this._sourcesContents = {};
         }
         this._sourcesContents[util.toSetString(source)] = aSourceContent;
-      } else {
+      } else if (this._sourcesContents) {
         // Remove the source file from the _sourcesContents map.
         // If the _sourcesContents map is empty, set the property to null.
         delete this._sourcesContents[util.toSetString(source)];
@@ -164,60 +164,59 @@ define(function (require, exports, module) {
    */
   SourceMapGenerator.prototype.applySourceMap =
     function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) {
+      var sourceFile = aSourceFile;
       // If aSourceFile is omitted, we will use the file property of the SourceMap
-      if (!aSourceFile) {
-        if (!aSourceMapConsumer.file) {
+      if (aSourceFile == null) {
+        if (aSourceMapConsumer.file == null) {
           throw new Error(
             'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' +
             'or the source map\'s "file" property. Both were omitted.'
           );
         }
-        aSourceFile = aSourceMapConsumer.file;
+        sourceFile = aSourceMapConsumer.file;
       }
       var sourceRoot = this._sourceRoot;
-      // Make "aSourceFile" relative if an absolute Url is passed.
-      if (sourceRoot) {
-        aSourceFile = util.relative(sourceRoot, aSourceFile);
+      // Make "sourceFile" relative if an absolute Url is passed.
+      if (sourceRoot != null) {
+        sourceFile = util.relative(sourceRoot, sourceFile);
       }
       // Applying the SourceMap can add and remove items from the sources and
       // the names array.
       var newSources = new ArraySet();
       var newNames = new ArraySet();
 
-      // Find mappings for the "aSourceFile"
+      // Find mappings for the "sourceFile"
       this._mappings.forEach(function (mapping) {
-        if (mapping.source === aSourceFile && mapping.originalLine) {
+        if (mapping.source === sourceFile && mapping.originalLine != null) {
           // Check if it can be mapped by the source map, then update the mapping.
           var original = aSourceMapConsumer.originalPositionFor({
             line: mapping.originalLine,
             column: mapping.originalColumn
           });
-          if (original.source !== null) {
+          if (original.source != null) {
             // Copy mapping
             mapping.source = original.source;
-            if (aSourceMapPath) {
+            if (aSourceMapPath != null) {
               mapping.source = util.join(aSourceMapPath, mapping.source)
             }
-            if (sourceRoot) {
+            if (sourceRoot != null) {
               mapping.source = util.relative(sourceRoot, mapping.source);
             }
             mapping.originalLine = original.line;
             mapping.originalColumn = original.column;
-            if (original.name !== null && mapping.name !== null) {
-              // Only use the identifier name if it's an identifier
-              // in both SourceMaps
+            if (original.name != null) {
               mapping.name = original.name;
             }
           }
         }
 
         var source = mapping.source;
-        if (source && !newSources.has(source)) {
+        if (source != null && !newSources.has(source)) {
           newSources.add(source);
         }
 
         var name = mapping.name;
-        if (name && !newNames.has(name)) {
+        if (name != null && !newNames.has(name)) {
           newNames.add(name);
         }
 
@@ -228,11 +227,11 @@ define(function (require, exports, module) {
       // Copy sourcesContents of applied map.
       aSourceMapConsumer.sources.forEach(function (sourceFile) {
         var content = aSourceMapConsumer.sourceContentFor(sourceFile);
-        if (content) {
-          if (aSourceMapPath) {
+        if (content != null) {
+          if (aSourceMapPath != null) {
             sourceFile = util.join(aSourceMapPath, sourceFile);
           }
-          if (sourceRoot) {
+          if (sourceRoot != null) {
             sourceFile = util.relative(sourceRoot, sourceFile);
           }
           this.setSourceContent(sourceFile, content);
@@ -323,7 +322,7 @@ define(function (require, exports, module) {
                                    - previousGeneratedColumn);
         previousGeneratedColumn = mapping.generatedColumn;
 
-        if (mapping.source) {
+        if (mapping.source != null) {
           result += base64VLQ.encode(this._sources.indexOf(mapping.source)
                                      - previousSource);
           previousSource = this._sources.indexOf(mapping.source);
@@ -337,7 +336,7 @@ define(function (require, exports, module) {
                                      - previousOriginalColumn);
           previousOriginalColumn = mapping.originalColumn;
 
-          if (mapping.name) {
+          if (mapping.name != null) {
             result += base64VLQ.encode(this._names.indexOf(mapping.name)
                                        - previousName);
             previousName = this._names.indexOf(mapping.name);
@@ -354,7 +353,7 @@ define(function (require, exports, module) {
         if (!this._sourcesContents) {
           return null;
         }
-        if (aSourceRoot) {
+        if (aSourceRoot != null) {
           source = util.relative(aSourceRoot, source);
         }
         var key = util.toSetString(source);
@@ -372,12 +371,14 @@ define(function (require, exports, module) {
     function SourceMapGenerator_toJSON() {
       var map = {
         version: this._version,
-        file: this._file,
         sources: this._sources.toArray(),
         names: this._names.toArray(),
         mappings: this._serializeMappings()
       };
-      if (this._sourceRoot) {
+      if (this._file != null) {
+        map.file = this._file;
+      }
+      if (this._sourceRoot != null) {
         map.sourceRoot = this._sourceRoot;
       }
       if (this._sourcesContents) {
diff --git a/lib/source-map/source-node.js b/lib/source-map/source-node.js
index 66a2ebc..baa5f40 100644
--- a/lib/source-map/source-node.js
+++ b/lib/source-map/source-node.js
@@ -14,7 +14,7 @@ define(function (require, exports, module) {
 
   // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other
   // operating systems these days (capturing the result).
-  var REGEX_NEWLINE = /(\r?\n)/g;
+  var REGEX_NEWLINE = /(\r?\n)/;
 
   // Matches a Windows-style newline, or any character.
   var REGEX_CHARACTER = /\r\n|[\s\S]/g;
@@ -34,10 +34,10 @@ define(function (require, exports, module) {
   function SourceNode(aLine, aColumn, aSource, aChunks, aName) {
     this.children = [];
     this.sourceContents = {};
-    this.line = aLine === undefined ? null : aLine;
-    this.column = aColumn === undefined ? null : aColumn;
-    this.source = aSource === undefined ? null : aSource;
-    this.name = aName === undefined ? null : aName;
+    this.line = aLine == null ? null : aLine;
+    this.column = aColumn == null ? null : aColumn;
+    this.source = aSource == null ? null : aSource;
+    this.name = aName == null ? null : aName;
     if (aChunks != null) this.add(aChunks);
   }
 
@@ -46,9 +46,11 @@ define(function (require, exports, module) {
    *
    * @param aGeneratedCode The generated code
    * @param aSourceMapConsumer The SourceMap for the generated code
+   * @param aRelativePath Optional. The path that relative sources in the
+   *        SourceMapConsumer should be relative to.
    */
   SourceNode.fromStringWithSourceMap =
-    function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) {
+    function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) {
       // The SourceNode we want to fill with the generated code
       // and the SourceMap
       var node = new SourceNode();
@@ -128,7 +130,10 @@ define(function (require, exports, module) {
       // Copy sourcesContent into SourceNode
       aSourceMapConsumer.sources.forEach(function (sourceFile) {
         var content = aSourceMapConsumer.sourceContentFor(sourceFile);
-        if (content) {
+        if (content != null) {
+          if (aRelativePath != null) {
+            sourceFile = util.join(aRelativePath, sourceFile);
+          }
           node.setSourceContent(sourceFile, content);
         }
       });
@@ -139,9 +144,12 @@ define(function (require, exports, module) {
         if (mapping === null || mapping.source === undefined) {
           node.add(code);
         } else {
+          var source = aRelativePath
+            ? util.join(aRelativePath, mapping.source)
+            : mapping.source;
           node.add(new SourceNode(mapping.originalLine,
                                   mapping.originalColumn,
-                                  mapping.source,
+                                  source,
                                   code,
                                   mapping.name));
         }
diff --git a/lib/source-map/util.js b/lib/source-map/util.js
index 4316445..976f6ca 100644
--- a/lib/source-map/util.js
+++ b/lib/source-map/util.js
@@ -143,6 +143,12 @@ define(function (require, exports, module) {
    * - 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) {
@@ -180,6 +186,31 @@ define(function (require, exports, module) {
   exports.join = join;
 
   /**
+   * 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(/\/$/, '');
+
+    // XXX: It is possible to remove this block, and the tests still pass!
+    var url = urlParse(aRoot);
+    if (aPath.charAt(0) == "/" && url && url.path == "/") {
+      return aPath.slice(1);
+    }
+
+    return aPath.indexOf(aRoot + '/') === 0
+      ? aPath.substr(aRoot.length + 1)
+      : aPath;
+  }
+  exports.relative = relative;
+
+  /**
    * Because behavior goes wacky when you set `__proto__` on objects, we
    * have to prefix all the strings in our set with an arbitrary character.
    *
@@ -198,20 +229,6 @@ define(function (require, exports, module) {
   }
   exports.fromSetString = fromSetString;
 
-  function relative(aRoot, aPath) {
-    aRoot = aRoot.replace(/\/$/, '');
-
-    var url = urlParse(aRoot);
-    if (aPath.charAt(0) == "/" && url && url.path == "/") {
-      return aPath.slice(1);
-    }
-
-    return aPath.indexOf(aRoot + '/') === 0
-      ? aPath.substr(aRoot.length + 1)
-      : aPath;
-  }
-  exports.relative = relative;
-
   function strcmp(aStr1, aStr2) {
     var s1 = aStr1 || "";
     var s2 = aStr2 || "";
diff --git a/package.json b/package.json
index 423a4e2..f337b45 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "source-map",
   "description": "Generates and consumes source maps",
-  "version": "0.1.34",
+  "version": "0.1.40",
   "homepage": "https://github.com/mozilla/source-map",
   "author": "Nick Fitzgerald <nfitzgerald at mozilla.com>",
   "contributors": [
@@ -25,7 +25,11 @@
     "David Glasser <glasser at davidglasser.net>",
     "Simon Lydell <simon.lydell at gmail.com>",
     "Jmeas Smith <jellyes2 at gmail.com>",
-    "Michael Z Goddard <mzgoddard at gmail.com>"
+    "Michael Z Goddard <mzgoddard at gmail.com>",
+    "azu <azu at users.noreply.github.com>",
+    "John Gozde <john at gozde.ca>",
+    "Adam Kirkton <akirkton at truefitinnovation.com>",
+    "Chris Montgomery <christopher.montgomery at dowjones.com>"
   ],
   "repository": {
     "type": "git",
diff --git a/test/source-map/test-base64-vlq.js b/test/source-map/test-base64-vlq.js
index 653a874..6fd0d99 100644
--- a/test/source-map/test-base64-vlq.js
+++ b/test/source-map/test-base64-vlq.js
@@ -12,10 +12,9 @@ define(function (require, exports, module) {
   var base64VLQ = require('../../lib/source-map/base64-vlq');
 
   exports['test normal encoding and decoding'] = function (assert, util) {
-    var result;
+    var result = {};
     for (var i = -255; i < 256; i++) {
-      result = base64VLQ.decode(base64VLQ.encode(i));
-      assert.ok(result);
+      base64VLQ.decode(base64VLQ.encode(i), result);
       assert.equal(result.value, i);
       assert.equal(result.rest, "");
     }
diff --git a/test/source-map/test-source-map-consumer.js b/test/source-map/test-source-map-consumer.js
index acd24d5..a4c6659 100644
--- a/test/source-map/test-source-map-consumer.js
+++ b/test/source-map/test-source-map-consumer.js
@@ -22,18 +22,34 @@ define(function (require, exports, module) {
   };
 
   exports['test that the `sources` field has the original sources'] = function (assert, util) {
-    var map = new SourceMapConsumer(util.testMap);
-    var sources = map.sources;
+    var map;
+    var sources;
 
+    map = new SourceMapConsumer(util.testMap);
+    sources = map.sources;
     assert.equal(sources[0], '/the/root/one.js');
     assert.equal(sources[1], '/the/root/two.js');
     assert.equal(sources.length, 2);
+
+    map = new SourceMapConsumer(util.testMapNoSourceRoot);
+    sources = map.sources;
+    assert.equal(sources[0], 'one.js');
+    assert.equal(sources[1], 'two.js');
+    assert.equal(sources.length, 2);
+
+    map = new SourceMapConsumer(util.testMapEmptySourceRoot);
+    sources = map.sources;
+    assert.equal(sources[0], 'one.js');
+    assert.equal(sources[1], 'two.js');
+    assert.equal(sources.length, 2);
   };
 
   exports['test that the source root is reflected in a mapping\'s source field'] = function (assert, util) {
-    var map = new SourceMapConsumer(util.testMap);
+    var map;
     var mapping;
 
+    map = new SourceMapConsumer(util.testMap);
+
     mapping = map.originalPositionFor({
       line: 2,
       column: 1
@@ -45,6 +61,36 @@ define(function (require, exports, module) {
       column: 1
     });
     assert.equal(mapping.source, '/the/root/one.js');
+
+
+    map = new SourceMapConsumer(util.testMapNoSourceRoot);
+
+    mapping = map.originalPositionFor({
+      line: 2,
+      column: 1
+    });
+    assert.equal(mapping.source, 'two.js');
+
+    mapping = map.originalPositionFor({
+      line: 1,
+      column: 1
+    });
+    assert.equal(mapping.source, 'one.js');
+
+
+    map = new SourceMapConsumer(util.testMapEmptySourceRoot);
+
+    mapping = map.originalPositionFor({
+      line: 2,
+      column: 1
+    });
+    assert.equal(mapping.source, 'two.js');
+
+    mapping = map.originalPositionFor({
+      line: 1,
+      column: 1
+    });
+    assert.equal(mapping.source, 'one.js');
   };
 
   exports['test mapping tokens back exactly'] = function (assert, util) {
@@ -111,15 +157,15 @@ define(function (require, exports, module) {
   };
 
   exports['test eachMapping'] = function (assert, util) {
-    var map = new SourceMapConsumer(util.testMap);
+    var map;
+
+    map = new SourceMapConsumer(util.testMap);
     var previousLine = -Infinity;
     var previousColumn = -Infinity;
     map.eachMapping(function (mapping) {
       assert.ok(mapping.generatedLine >= previousLine);
 
-      if (mapping.source) {
-        assert.equal(mapping.source.indexOf(util.testMap.sourceRoot), 0);
-      }
+      assert.ok(mapping.source === '/the/root/one.js' || mapping.source === '/the/root/two.js');
 
       if (mapping.generatedLine === previousLine) {
         assert.ok(mapping.generatedColumn >= previousColumn);
@@ -130,6 +176,16 @@ define(function (require, exports, module) {
         previousColumn = -Infinity;
       }
     });
+
+    map = new SourceMapConsumer(util.testMapNoSourceRoot);
+    map.eachMapping(function (mapping) {
+      assert.ok(mapping.source === 'one.js' || mapping.source === 'two.js');
+    });
+
+    map = new SourceMapConsumer(util.testMapEmptySourceRoot);
+    map.eachMapping(function (mapping) {
+      assert.ok(mapping.source === 'one.js' || mapping.source === 'two.js');
+    });
   };
 
   exports['test iterating over mappings in a different order'] = function (assert, util) {
diff --git a/test/source-map/test-source-map-generator.js b/test/source-map/test-source-map-generator.js
index 227140f..a0d9d00 100644
--- a/test/source-map/test-source-map-generator.js
+++ b/test/source-map/test-source-map-generator.js
@@ -21,8 +21,9 @@ define(function (require, exports, module) {
     });
     assert.ok(true);
 
-    var map = new SourceMapGenerator();
-    assert.ok(true);
+    var map = new SourceMapGenerator().toJSON();
+    assert.ok(!('file' in map));
+    assert.ok(!('sourceRoot' in map));
   };
 
   exports['test JSON serialization'] = function (assert, util) {
@@ -180,6 +181,24 @@ define(function (require, exports, module) {
     util.assertEqualMaps(assert, map, util.testMap);
   };
 
+  exports['test that adding a mapping with an empty string name does not break generation'] = function (assert, util) {
+    var map = new SourceMapGenerator({
+      file: 'generated-foo.js',
+      sourceRoot: '.'
+    });
+
+    map.addMapping({
+      generated: { line: 1, column: 1 },
+      source: 'bar.js',
+      original: { line: 1, column: 1 },
+      name: ''
+    });
+
+    assert.doesNotThrow(function () {
+      JSON.parse(map.toString());
+    });
+  };
+
   exports['test that source content can be set'] = function (assert, util) {
     var map = new SourceMapGenerator({
       file: 'min.js',
@@ -292,8 +311,8 @@ define(function (require, exports, module) {
     //       foo.coffee
     //     temp/
     //       bundle.js
-    //     temp_maps/
-    //       bundle.js.map
+    //       temp_maps/
+    //         bundle.js.map
     //     public/
     //       bundle.min.js
     //       bundle.min.js.map
@@ -307,9 +326,9 @@ define(function (require, exports, module) {
     bundleMap.addMapping({
       generated: { line: 3, column: 3 },
       original: { line: 2, column: 2 },
-      source: '../coffee/foo.coffee'
+      source: '../../coffee/foo.coffee'
     });
-    bundleMap.setSourceContent('../coffee/foo.coffee', 'foo coffee');
+    bundleMap.setSourceContent('../../coffee/foo.coffee', 'foo coffee');
     bundleMap.addMapping({
       generated: { line: 13, column: 13 },
       original: { line: 12, column: 12 },
@@ -382,23 +401,106 @@ define(function (require, exports, module) {
       return map.toJSON();
     }
 
-    util.assertEqualMaps(assert, actualMap('../temp_maps'), expectedMap([
+    util.assertEqualMaps(assert, actualMap('../temp/temp_maps'), expectedMap([
       'coffee/foo.coffee',
       '/bar.coffee',
       'http://www.example.com/baz.coffee'
     ]));
 
-    util.assertEqualMaps(assert, actualMap('/app/temp_maps'), expectedMap([
+    util.assertEqualMaps(assert, actualMap('/app/temp/temp_maps'), expectedMap([
       '/app/coffee/foo.coffee',
       '/bar.coffee',
       'http://www.example.com/baz.coffee'
     ]));
 
-    util.assertEqualMaps(assert, actualMap('http://foo.org/app/temp_maps'), expectedMap([
+    util.assertEqualMaps(assert, actualMap('http://foo.org/app/temp/temp_maps'), expectedMap([
       'http://foo.org/app/coffee/foo.coffee',
       'http://foo.org/bar.coffee',
       'http://www.example.com/baz.coffee'
     ]));
+
+    // If the third parameter is omitted or set to the current working
+    // directory we get incorrect source paths:
+
+    util.assertEqualMaps(assert, actualMap(), expectedMap([
+      '../coffee/foo.coffee',
+      '/bar.coffee',
+      'http://www.example.com/baz.coffee'
+    ]));
+
+    util.assertEqualMaps(assert, actualMap(''), expectedMap([
+      '../coffee/foo.coffee',
+      '/bar.coffee',
+      'http://www.example.com/baz.coffee'
+    ]));
+
+    util.assertEqualMaps(assert, actualMap('.'), expectedMap([
+      '../coffee/foo.coffee',
+      '/bar.coffee',
+      'http://www.example.com/baz.coffee'
+    ]));
+
+    util.assertEqualMaps(assert, actualMap('./'), expectedMap([
+      '../coffee/foo.coffee',
+      '/bar.coffee',
+      'http://www.example.com/baz.coffee'
+    ]));
+  };
+
+  exports['test applySourceMap name handling'] = function (assert, util) {
+    // Imagine some CoffeeScript code being compiled into JavaScript and then
+    // minified.
+
+    var assertName = function(coffeeName, jsName, expectedName) {
+      var minifiedMap = new SourceMapGenerator({
+        file: 'test.js.min'
+      });
+      minifiedMap.addMapping({
+        generated: { line: 1, column: 4 },
+        original: { line: 1, column: 4 },
+        source: 'test.js',
+        name: jsName
+      });
+
+      var coffeeMap = new SourceMapGenerator({
+        file: 'test.js'
+      });
+      coffeeMap.addMapping({
+        generated: { line: 1, column: 4 },
+        original: { line: 1, column: 0 },
+        source: 'test.coffee',
+        name: coffeeName
+      });
+
+      minifiedMap.applySourceMap(new SourceMapConsumer(coffeeMap.toJSON()));
+
+      new SourceMapConsumer(minifiedMap.toJSON()).eachMapping(function(mapping) {
+        assert.equal(mapping.name, expectedName);
+      });
+    };
+
+    // `foo = 1` -> `var foo = 1;` -> `var a=1`
+    // CoffeeScript doesn’t rename variables, so there’s no need for it to
+    // provide names in its source maps. Minifiers do rename variables and
+    // therefore do provide names in their source maps. So that name should be
+    // retained if the original map lacks names.
+    assertName(null, 'foo', 'foo');
+
+    // `foo = 1` -> `var coffee$foo = 1;` -> `var a=1`
+    // Imagine that CoffeeScript prefixed all variables with `coffee$`. Even
+    // though the minifier then also provides a name, the original name is
+    // what corresponds to the source.
+    assertName('foo', 'coffee$foo', 'foo');
+
+    // `foo = 1` -> `var coffee$foo = 1;` -> `var coffee$foo=1`
+    // Minifiers can turn off variable mangling. Then there’s no need to
+    // provide names in the source map, but the names from the original map are
+    // still needed.
+    assertName('foo', null, 'foo');
+
+    // `foo = 1` -> `var foo = 1;` -> `var foo=1`
+    // No renaming at all.
+    assertName(null, null, null);
   };
 
   exports['test sorting with duplicate generated mappings'] = function (assert, util) {
@@ -546,4 +648,11 @@ define(function (require, exports, module) {
     });
   };
 
+  exports['test setting sourcesContent to null when already null'] = function (assert, util) {
+    var smg = new SourceMapGenerator({ file: "foo.js" });
+    assert.doesNotThrow(function() {
+      smg.setSourceContent("bar.js", null);
+    });
+  };
+
 });
diff --git a/test/source-map/test-source-node.js b/test/source-map/test-source-node.js
index d186521..139af4e 100644
--- a/test/source-map/test-source-node.js
+++ b/test/source-map/test-source-node.js
@@ -159,6 +159,7 @@ define(function (require, exports, module) {
 
     assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator');
     assert.ok(mapWithoutOptions instanceof SourceMapGenerator, 'mapWithoutOptions instanceof SourceMapGenerator');
+    assert.ok(!('file' in mapWithoutOptions));
     mapWithoutOptions._file = 'foo.js';
     util.assertEqualMaps(assert, map.toJSON(), mapWithoutOptions.toJSON());
 
@@ -276,6 +277,94 @@ define(function (require, exports, module) {
     util.assertEqualMaps(assert, map, inputMap);
   });
 
+  exports['test .fromStringWithSourceMap() third argument'] = function (assert, util) {
+    // Assume the following directory structure:
+    //
+    // http://foo.org/
+    //   bar.coffee
+    //   app/
+    //     coffee/
+    //       foo.coffee
+    //       coffeeBundle.js # Made from {foo,bar,baz}.coffee
+    //       maps/
+    //         coffeeBundle.js.map
+    //     js/
+    //       foo.js
+    //     public/
+    //       app.js # Made from {foo,coffeeBundle}.js
+    //       app.js.map
+    //
+    // http://www.example.com/
+    //   baz.coffee
+
+    var coffeeBundle = new SourceNode(1, 0, 'foo.coffee', 'foo(coffee);\n');
+    coffeeBundle.setSourceContent('foo.coffee', 'foo coffee');
+    coffeeBundle.add(new SourceNode(2, 0, '/bar.coffee', 'bar(coffee);\n'));
+    coffeeBundle.add(new SourceNode(3, 0, 'http://www.example.com/baz.coffee', 'baz(coffee);'));
+    coffeeBundle = coffeeBundle.toStringWithSourceMap({
+      file: 'foo.js',
+      sourceRoot: '..'
+    });
+
+    var foo = new SourceNode(1, 0, 'foo.js', 'foo(js);');
+
+    var test = function(relativePath, expectedSources) {
+      var app = new SourceNode();
+      app.add(SourceNode.fromStringWithSourceMap(
+                                coffeeBundle.code,
+                                new SourceMapConsumer(coffeeBundle.map.toString()),
+                                relativePath));
+      app.add(foo);
+      var i = 0;
+      app.walk(function (chunk, loc) {
+        assert.equal(loc.source, expectedSources[i]);
+        i++;
+      });
+      app.walkSourceContents(function (sourceFile, sourceContent) {
+        assert.equal(sourceFile, expectedSources[0]);
+        assert.equal(sourceContent, 'foo coffee');
+      })
+    };
+
+    test('../coffee/maps', [
+      '../coffee/foo.coffee',
+      '/bar.coffee',
+      'http://www.example.com/baz.coffee',
+      'foo.js'
+    ]);
+
+    // If the third parameter is omitted or set to the current working
+    // directory we get incorrect source paths:
+
+    test(undefined, [
+      '../foo.coffee',
+      '/bar.coffee',
+      'http://www.example.com/baz.coffee',
+      'foo.js'
+    ]);
+
+    test('', [
+      '../foo.coffee',
+      '/bar.coffee',
+      'http://www.example.com/baz.coffee',
+      'foo.js'
+    ]);
+
+    test('.', [
+      '../foo.coffee',
+      '/bar.coffee',
+      'http://www.example.com/baz.coffee',
+      'foo.js'
+    ]);
+
+    test('./', [
+      '../foo.coffee',
+      '/bar.coffee',
+      'http://www.example.com/baz.coffee',
+      'foo.js'
+    ]);
+  };
+
   exports['test .toStringWithSourceMap() merging duplicate mappings'] = forEachNewline(function (assert, util, nl) {
     var input = new SourceNode(null, null, null, [
       new SourceNode(1, 0, "a.js", "(function"),
@@ -441,6 +530,42 @@ define(function (require, exports, module) {
     assert.equal(result.code, '');
   };
 
+  exports['test .toStringWithSourceMap() with consecutive newlines'] = forEachNewline(function (assert, util, nl) {
+    var input = new SourceNode(null, null, null, [
+      "/***/" + nl + nl,
+      new SourceNode(1, 0, "a.js", "'use strict';" + nl),
+      new SourceNode(2, 0, "a.js", "a();"),
+    ]);
+    input = input.toStringWithSourceMap({
+      file: 'foo.js'
+    });
+
+    assert.equal(input.code, [
+      "/***/",
+      "",
+      "'use strict';",
+      "a();",
+    ].join(nl));
+
+    var correctMap = new SourceMapGenerator({
+      file: 'foo.js'
+    });
+    correctMap.addMapping({
+      generated: { line: 3, column: 0 },
+      source: 'a.js',
+      original: { line: 1, column: 0 }
+    });
+    correctMap.addMapping({
+      generated: { line: 4, column: 0 },
+      source: 'a.js',
+      original: { line: 2, column: 0 }
+    });
+
+    var inputMap = input.map.toJSON();
+    correctMap = correctMap.toJSON();
+    util.assertEqualMaps(assert, inputMap, correctMap);
+  });
+
   exports['test setSourceContent with toStringWithSourceMap'] = function (assert, util) {
     var aNode = new SourceNode(1, 1, 'a.js', 'a');
     aNode.setSourceContent('a.js', 'someContent');
diff --git a/test/source-map/test-util.js b/test/source-map/test-util.js
index 22e9a9e..997d1a2 100644
--- a/test/source-map/test-util.js
+++ b/test/source-map/test-util.js
@@ -28,7 +28,14 @@ define(function (require, exports, module) {
     assertUrl('//www.example.com');
     assertUrl('file:///www.example.com');
 
+    assert.equal(libUtil.urlParse(''), null);
+    assert.equal(libUtil.urlParse('.'), null);
+    assert.equal(libUtil.urlParse('..'), null);
+    assert.equal(libUtil.urlParse('a'), null);
+    assert.equal(libUtil.urlParse('a/b'), null);
     assert.equal(libUtil.urlParse('a//b'), null);
+    assert.equal(libUtil.urlParse('/a'), null);
+    assert.equal(libUtil.urlParse('data:foo,bar'), null);
   };
 
   exports['test normalize()'] = function (assert, util) {
@@ -50,6 +57,7 @@ define(function (require, exports, module) {
     assert.equal(libUtil.normalize('/././././a/b/c'), '/a/b/c');
     assert.equal(libUtil.normalize('/a/b/c/./././d/././e'), '/a/b/c/d/e');
 
+    assert.equal(libUtil.normalize(''), '.');
     assert.equal(libUtil.normalize('.'), '.');
     assert.equal(libUtil.normalize('./'), '.');
     assert.equal(libUtil.normalize('././a'), 'a');
@@ -88,6 +96,73 @@ define(function (require, exports, module) {
     assert.equal(libUtil.join('a', 'data:foo,bar'), 'data:foo,bar');
 
 
+    assert.equal(libUtil.join('', 'b'), 'b');
+    assert.equal(libUtil.join('.', 'b'), 'b');
+    assert.equal(libUtil.join('', 'b/'), 'b/');
+    assert.equal(libUtil.join('.', 'b/'), 'b/');
+    assert.equal(libUtil.join('', 'b//'), 'b/');
+    assert.equal(libUtil.join('.', 'b//'), 'b/');
+
+    assert.equal(libUtil.join('', '..'), '..');
+    assert.equal(libUtil.join('.', '..'), '..');
+    assert.equal(libUtil.join('', '../b'), '../b');
+    assert.equal(libUtil.join('.', '../b'), '../b');
+
+    assert.equal(libUtil.join('', '.'), '.');
+    assert.equal(libUtil.join('.', '.'), '.');
+    assert.equal(libUtil.join('', './b'), 'b');
+    assert.equal(libUtil.join('.', './b'), 'b');
+
+    assert.equal(libUtil.join('', 'http://www.example.com'), 'http://www.example.com');
+    assert.equal(libUtil.join('.', 'http://www.example.com'), 'http://www.example.com');
+    assert.equal(libUtil.join('', 'data:foo,bar'), 'data:foo,bar');
+    assert.equal(libUtil.join('.', 'data:foo,bar'), 'data:foo,bar');
+
+
+    assert.equal(libUtil.join('..', 'b'), '../b');
+    assert.equal(libUtil.join('..', 'b/'), '../b/');
+    assert.equal(libUtil.join('..', 'b//'), '../b/');
+
+    assert.equal(libUtil.join('..', '..'), '../..');
+    assert.equal(libUtil.join('..', '../b'), '../../b');
+
+    assert.equal(libUtil.join('..', '.'), '..');
+    assert.equal(libUtil.join('..', './b'), '../b');
+
+    assert.equal(libUtil.join('..', 'http://www.example.com'), 'http://www.example.com');
+    assert.equal(libUtil.join('..', 'data:foo,bar'), 'data:foo,bar');
+
+
+    assert.equal(libUtil.join('a', ''), 'a');
+    assert.equal(libUtil.join('a', '.'), 'a');
+    assert.equal(libUtil.join('a/', ''), 'a');
+    assert.equal(libUtil.join('a/', '.'), 'a');
+    assert.equal(libUtil.join('a//', ''), 'a');
+    assert.equal(libUtil.join('a//', '.'), 'a');
+    assert.equal(libUtil.join('/a', ''), '/a');
+    assert.equal(libUtil.join('/a', '.'), '/a');
+    assert.equal(libUtil.join('', ''), '.');
+    assert.equal(libUtil.join('.', ''), '.');
+    assert.equal(libUtil.join('.', ''), '.');
+    assert.equal(libUtil.join('.', '.'), '.');
+    assert.equal(libUtil.join('..', ''), '..');
+    assert.equal(libUtil.join('..', '.'), '..');
+    assert.equal(libUtil.join('http://foo.org/a', ''), 'http://foo.org/a');
+    assert.equal(libUtil.join('http://foo.org/a', '.'), 'http://foo.org/a');
+    assert.equal(libUtil.join('http://foo.org/a/', ''), 'http://foo.org/a');
+    assert.equal(libUtil.join('http://foo.org/a/', '.'), 'http://foo.org/a');
+    assert.equal(libUtil.join('http://foo.org/a//', ''), 'http://foo.org/a');
+    assert.equal(libUtil.join('http://foo.org/a//', '.'), 'http://foo.org/a');
+    assert.equal(libUtil.join('http://foo.org', ''), 'http://foo.org/');
+    assert.equal(libUtil.join('http://foo.org', '.'), 'http://foo.org/');
+    assert.equal(libUtil.join('http://foo.org/', ''), 'http://foo.org/');
+    assert.equal(libUtil.join('http://foo.org/', '.'), 'http://foo.org/');
+    assert.equal(libUtil.join('http://foo.org//', ''), 'http://foo.org/');
+    assert.equal(libUtil.join('http://foo.org//', '.'), 'http://foo.org/');
+    assert.equal(libUtil.join('//www.example.com', ''), '//www.example.com/');
+    assert.equal(libUtil.join('//www.example.com', '.'), '//www.example.com/');
+
+
     assert.equal(libUtil.join('http://foo.org/a', 'b'), 'http://foo.org/a/b');
     assert.equal(libUtil.join('http://foo.org/a/', 'b'), 'http://foo.org/a/b');
     assert.equal(libUtil.join('http://foo.org/a//', 'b'), 'http://foo.org/a/b');
@@ -124,4 +199,18 @@ define(function (require, exports, module) {
     assert.equal(libUtil.join('//www.example.com', '//foo.org/bar'), '//foo.org/bar');
   };
 
+  // TODO Issue #128: Define and test this function properly.
+  exports['test relative()'] = function (assert, util) {
+    assert.equal(libUtil.relative('/the/root', '/the/root/one.js'), 'one.js');
+    assert.equal(libUtil.relative('/the/root', '/the/rootone.js'), '/the/rootone.js');
+
+    assert.equal(libUtil.relative('', '/the/root/one.js'), '/the/root/one.js');
+    assert.equal(libUtil.relative('.', '/the/root/one.js'), '/the/root/one.js');
+    assert.equal(libUtil.relative('', 'the/root/one.js'), 'the/root/one.js');
+    assert.equal(libUtil.relative('.', 'the/root/one.js'), 'the/root/one.js');
+
+    assert.equal(libUtil.relative('/', '/the/root/one.js'), 'the/root/one.js');
+    assert.equal(libUtil.relative('/', 'the/root/one.js'), 'the/root/one.js');
+  };
+
 });
diff --git a/test/source-map/util.js b/test/source-map/util.js
index 288046b..fa213ce 100644
--- a/test/source-map/util.js
+++ b/test/source-map/util.js
@@ -40,6 +40,21 @@ define(function (require, exports, module) {
     sourceRoot: '/the/root',
     mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'
   };
+  exports.testMapNoSourceRoot = {
+    version: 3,
+    file: 'min.js',
+    names: ['bar', 'baz', 'n'],
+    sources: ['one.js', 'two.js'],
+    mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'
+  };
+  exports.testMapEmptySourceRoot = {
+    version: 3,
+    file: 'min.js',
+    names: ['bar', 'baz', 'n'],
+    sources: ['one.js', 'two.js'],
+    sourceRoot: '',
+    mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'
+  };
   exports.testMapWithSourcesContent = {
     version: 3,
     file: 'min.js',

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-source-map.git



More information about the Pkg-javascript-commits mailing list