From dedaf846ee197ab5037efbd7ec26dda35b3ec978 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Thu, 18 Feb 2016 11:45:47 -0800 Subject: [PATCH 1/8] Update tests to run on Windows --- test.js | 80 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/test.js b/test.js index 1315c9f..81effcf 100644 --- a/test.js +++ b/test.js @@ -110,7 +110,7 @@ function compareStdout(done, sourceMap, source, expected) { compareLines( (stdout + stderr) .trim() - .split('\n') + .split(/\r\n|\r|\n/g) .filter(function (line) { return line !== '' }), // Empty lines are not relevant. expected ); @@ -129,7 +129,7 @@ it('normal throw', function() { 'throw new Error("test");' ], [ 'Error: test', - /^ at Object\.exports\.test \(.*\/line1\.js:1001:101\)$/ + /^ at Object\.exports\.test \(.*[\\/]line1\.js:1001:101\)$/ ]); }); @@ -141,8 +141,8 @@ it('throw inside function', function() { 'foo();' ], [ 'Error: test', - /^ at foo \(.*\/line2\.js:1002:102\)$/, - /^ at Object\.exports\.test \(.*\/line4\.js:1004:104\)$/ + /^ at foo \(.*[\\/]line2\.js:1002:102\)$/, + /^ at Object\.exports\.test \(.*[\\/]line4\.js:1004:104\)$/ ]); }); @@ -157,9 +157,9 @@ it('throw inside function inside function', function() { 'foo();' ], [ 'Error: test', - /^ at bar \(.*\/line3\.js:1003:103\)$/, - /^ at foo \(.*\/line5\.js:1005:105\)$/, - /^ at Object\.exports\.test \(.*\/line7\.js:1007:107\)$/ + /^ at bar \(.*[\\/]line3\.js:1003:103\)$/, + /^ at foo \(.*[\\/]line5\.js:1005:105\)$/, + /^ at Object\.exports\.test \(.*[\\/]line7\.js:1007:107\)$/ ]); }); @@ -170,9 +170,9 @@ it('eval', function() { 'Error: test', // Before Node 4, `Object.eval`, after just `eval`. - /^ at (?:Object\.)?eval \(eval at \(.*\/line1\.js:1001:101\)/, + /^ at (?:Object\.)?eval \(eval at \(.*[\\/]line1\.js:1001:101\)/, - /^ at Object\.exports\.test \(.*\/line1\.js:1001:101\)$/ + /^ at Object\.exports\.test \(.*[\\/]line1\.js:1001:101\)$/ ]); }); @@ -181,9 +181,9 @@ it('eval inside eval', function() { 'eval("eval(\'throw new Error(\\"test\\")\')");' ], [ 'Error: test', - /^ at (?:Object\.)?eval \(eval at \(eval at \(.*\/line1\.js:1001:101\)/, - /^ at (?:Object\.)?eval \(eval at \(.*\/line1\.js:1001:101\)/, - /^ at Object\.exports\.test \(.*\/line1\.js:1001:101\)$/ + /^ at (?:Object\.)?eval \(eval at \(eval at \(.*[\\/]line1\.js:1001:101\)/, + /^ at (?:Object\.)?eval \(eval at \(.*[\\/]line1\.js:1001:101\)/, + /^ at Object\.exports\.test \(.*[\\/]line1\.js:1001:101\)$/ ]); }); @@ -195,9 +195,9 @@ it('eval inside function', function() { 'foo();' ], [ 'Error: test', - /^ at eval \(eval at foo \(.*\/line2\.js:1002:102\)/, - /^ at foo \(.*\/line2\.js:1002:102\)/, - /^ at Object\.exports\.test \(.*\/line4\.js:1004:104\)$/ + /^ at eval \(eval at foo \(.*[\\/]line2\.js:1002:102\)/, + /^ at foo \(.*[\\/]line2\.js:1002:102\)/, + /^ at Object\.exports\.test \(.*[\\/]line4\.js:1004:104\)$/ ]); }); @@ -207,7 +207,7 @@ it('eval with sourceURL', function() { ], [ 'Error: test', /^ at (?:Object\.)?eval \(sourceURL\.js:1:7\)$/, - /^ at Object\.exports\.test \(.*\/line1\.js:1001:101\)$/ + /^ at Object\.exports\.test \(.*[\\/]line1\.js:1001:101\)$/ ]); }); @@ -217,8 +217,8 @@ it('eval with sourceURL inside eval', function() { ], [ 'Error: test', /^ at (?:Object\.)?eval \(sourceURL\.js:1:7\)$/, - /^ at (?:Object\.)?eval \(eval at \(.*\/line1\.js:1001:101\)/, - /^ at Object\.exports\.test \(.*\/line1\.js:1001:101\)$/ + /^ at (?:Object\.)?eval \(eval at \(.*[\\/]line1\.js:1001:101\)/, + /^ at Object\.exports\.test \(.*[\\/]line1\.js:1001:101\)$/ ]); }); @@ -228,7 +228,7 @@ it('function constructor', function() { ], [ 'SyntaxError: Unexpected token )', /^ at (?:Object\.)?Function \((?:unknown source||native)\)$/, - /^ at Object\.exports\.test \(.*\/line1\.js:1001:101\)$/, + /^ at Object\.exports\.test \(.*[\\/]line1\.js:1001:101\)$/, ]); }); @@ -237,7 +237,7 @@ it('throw with empty source map', function() { 'throw new Error("test");' ], [ 'Error: test', - /^ at Object\.exports\.test \(.*\/.generated.js:1:34\)$/ + /^ at Object\.exports\.test \(.*[\\/].generated.js:1:34\)$/ ]); }); @@ -246,7 +246,7 @@ it('throw with source map with gap', function() { 'throw new Error("test");' ], [ 'Error: test', - /^ at Object\.exports\.test \(.*\/.generated.js:1:34\)$/ + /^ at Object\.exports\.test \(.*[\\/].generated.js:1:34\)$/ ]); }); @@ -255,7 +255,7 @@ it('sourcesContent with data URL', function() { 'throw new Error("test");' ], [ 'Error: test', - /^ at Object\.exports\.test \(.*\/original.js:1001:5\)$/ + /^ at Object\.exports\.test \(.*[\\/]original.js:1001:5\)$/ ]); }); @@ -265,7 +265,7 @@ it('finds the last sourceMappingURL', function() { 'throw new Error("test");' ], [ 'Error: test', - /^ at Object\.exports\.test \(.*\/original.js:1002:5\)$/ + /^ at Object\.exports\.test \(.*[\\/]original.js:1002:5\)$/ ]); }); @@ -277,11 +277,11 @@ it('default options', function(done) { 'process.nextTick(foo);', 'process.nextTick(function() { process.exit(1); });' ], [ - /\/.original\.js:1$/, + /[\\/].original\.js:1$/, 'this is the original code', '^', 'Error: this is the error', - /^ at foo \(.*\/.original\.js:1:1\)$/ + /^ at foo \(.*[\\/].original\.js:1:1\)$/ ]); }); @@ -292,11 +292,11 @@ it('handleUncaughtExceptions is true', function(done) { 'require("./source-map-support").install({ handleUncaughtExceptions: true });', 'process.nextTick(foo);' ], [ - /\/.original\.js:1$/, + /[\\/].original\.js:1$/, 'this is the original code', '^', 'Error: this is the error', - /^ at foo \(.*\/.original\.js:1:1\)$/ + /^ at foo \(.*[\\/].original\.js:1:1\)$/ ]); }); @@ -307,7 +307,7 @@ it('handleUncaughtExceptions is false', function(done) { 'require("./source-map-support").install({ handleUncaughtExceptions: false });', 'process.nextTick(foo);' ], [ - /\/.generated.js:2$/, + /[\\/].generated.js:2$/, 'function foo() { throw new Error("this is the error"); }', // Before Node 4, the arrow points on the `new`, after on the @@ -315,7 +315,7 @@ it('handleUncaughtExceptions is false', function(done) { /^ (?: )?\^$/, 'Error: this is the error', - /^ at foo \(.*\/.original\.js:1:1\)$/ + /^ at foo \(.*[\\/].original\.js:1:1\)$/ ]); }); @@ -326,11 +326,11 @@ it('default options with empty source map', function(done) { 'require("./source-map-support").install();', 'process.nextTick(foo);' ], [ - /\/.generated.js:2$/, + /[\\/].generated.js:2$/, 'function foo() { throw new Error("this is the error"); }', /^ (?: )?\^$/, 'Error: this is the error', - /^ at foo \(.*\/.generated.js:2:24\)$/ + /^ at foo \(.*[\\/].generated.js:2:24\)$/ ]); }); @@ -341,11 +341,11 @@ it('default options with source map with gap', function(done) { 'require("./source-map-support").install();', 'process.nextTick(foo);' ], [ - /\/.generated.js:2$/, + /[\\/].generated.js:2$/, 'function foo() { throw new Error("this is the error"); }', /^ (?: )?\^$/, 'Error: this is the error', - /^ at foo \(.*\/.generated.js:2:24\)$/ + /^ at foo \(.*[\\/].generated.js:2:24\)$/ ]); }); @@ -358,7 +358,7 @@ it('specifically requested error source', function(done) { 'process.on("uncaughtException", function (e) { console.log("SRC:" + sms.getErrorSource(e)); });', 'process.nextTick(foo);' ], [ - /^SRC:.*\/.original.js:1$/, + /^SRC:.*[\\/].original.js:1$/, 'this is the original code', '^' ]); @@ -372,11 +372,11 @@ it('sourcesContent', function(done) { 'process.nextTick(foo);', 'process.nextTick(function() { process.exit(1); });' ], [ - /\/original\.js:1002$/, + /[\\/]original\.js:1002$/, ' line 2', ' ^', 'Error: this is the error', - /^ at foo \(.*\/original\.js:1002:5\)$/ + /^ at foo \(.*[\\/]original\.js:1002:5\)$/ ]); }); @@ -399,9 +399,9 @@ it('missing source maps should also be cached', function(done) { 'process.nextTick(function() { console.log(count); });', ], [ 'Error: this is the error', - /^ at foo \(.*\/.generated.js:4:15\)$/, + /^ at foo \(.*[\\/].generated.js:4:15\)$/, 'Error: this is the error', - /^ at foo \(.*\/.generated.js:4:15\)$/, + /^ at foo \(.*[\\/].generated.js:4:15\)$/, '1', // The retrieval should only be attempted once ]); }); @@ -432,9 +432,9 @@ it('should consult all retrieve source map providers', function(done) { 'process.nextTick(function() { console.log(count); });', ], [ 'Error: this is the error', - /^ at foo \(.*\/original.js:1004:5\)$/, + /^ at foo \(.*[\\/]original.js:1004:5\)$/, 'Error: this is the error', - /^ at foo \(.*\/original.js:1004:5\)$/, + /^ at foo \(.*[\\/]original.js:1004:5\)$/, '1', // The retrieval should only be attempted once ]); }); From c3fbc76bad34a1a9e0bb3166b6caa25f62449082 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Thu, 18 Feb 2016 12:45:54 -0800 Subject: [PATCH 2/8] Added support for file urls --- browser-test/script.map | 2 +- source-map-support.js | 60 ++++++++++++++++++++++++++++++++++++----- test.js | 52 ++++++++++++++++++++++++++++++++--- 3 files changed, 104 insertions(+), 10 deletions(-) diff --git a/browser-test/script.map b/browser-test/script.map index 127a2b6..8fcb11e 100644 --- a/browser-test/script.map +++ b/browser-test/script.map @@ -3,7 +3,7 @@ "file": "script.js", "sourceRoot": "..", "sources": [ - "browser-test/script.coffee" + "browser-test\\script.coffee" ], "names": [], "mappings": ";AAAA;AAAA,MAAA,MAAA;;AAAA,EAAA,gBAAgB,CAAC,OAAjB,CAAA,CAAA,CAAA;;AAAA,EAEA,GAAA,GAAM,SAAA,GAAA;AAAG,UAAU,IAAA,KAAA,CAAM,KAAN,CAAV,CAAH;EAAA,CAFN,CAAA;;AAIA;AACE,IAAA,GAAA,CAAA,CAAA,CADF;GAAA,cAAA;AAGE,IADI,UACJ,CAAA;AAAA,IAAA,IAAG,oBAAoB,CAAC,IAArB,CAA0B,CAAC,CAAC,KAA5B,CAAH;AACE,MAAA,QAAQ,CAAC,IAAI,CAAC,WAAd,CAA0B,QAAQ,CAAC,cAAT,CAAwB,aAAxB,CAA1B,CAAA,CADF;KAAA,MAAA;AAGE,MAAA,QAAQ,CAAC,IAAI,CAAC,WAAd,CAA0B,QAAQ,CAAC,cAAT,CAAwB,aAAxB,CAA1B,CAAA,CAAA;AAAA,MACA,OAAO,CAAC,GAAR,CAAY,CAAC,CAAC,KAAd,CADA,CAHF;KAHF;GAJA;AAAA" diff --git a/source-map-support.js b/source-map-support.js index 49ed72d..1c74a9c 100644 --- a/source-map-support.js +++ b/source-map-support.js @@ -1,6 +1,7 @@ var SourceMapConsumer = require('source-map').SourceMapConsumer; var path = require('path'); var fs = require('fs'); +var url = require('url'); // Only install once if called multiple times var errorFormatterInstalled = false; @@ -72,6 +73,9 @@ retrieveFileHandlers.push(function(path) { // Otherwise, use the filesystem else { + if (isAbsoluteURL(path)) { + path = localURLPath(path); + } var contents = fs.readFileSync(path, 'utf8'); } } catch (e) { @@ -81,14 +85,58 @@ retrieveFileHandlers.push(function(path) { return fileContentsCache[path] = contents; }); +function isAbsoluteURL(file) { + if (/^\w+:\/\//i.test(file)) { + if (!isInBrowser()) { + var dir = path.dirname(file); + if (fs.existsSync(dir)) { + return false; + } + } + return true; + } + return false; +} + +function localURLPath(file) { + var parsed = url.parse(file); + if (parsed.protocol === 'file:') { + var local = decodeURIComponent(parsed.path); + if (parsed.hostname) { + // SAMBA path + return '//' + parsed.hostname + local + } + else if (/^\/\w[:|]/.test(local)) { + // DOS path + return local.slice(1, 2) + ':' + local.slice(3).replace(/\//g, '\\'); + } + else { + // POSIX path + return local; + } + } + + // Unhandled URL protocol, return it. + return file; +} + // Support URLs relative to a directory, but be careful about a protocol prefix // in case we are in the browser (i.e. directories may start with "http://") -function supportRelativeURL(file, url) { - if (!file) return url; - var dir = path.dirname(file); - var match = /^\w+:\/\/[^\/]*/.exec(dir); - var protocol = match ? match[0] : ''; - return protocol + path.resolve(dir.slice(protocol.length), url); +function supportRelativeURL(base, relative) { + if (!base) { + return relative; + } + if (isAbsoluteURL(base)) { + // base is a url, use url to combine. + return url.resolve(base, relative); + } + if (isAbsoluteURL(relative)) { + // absolute url or DOS path + return relative; + } + + var dir = path.dirname(base); + return path.resolve(dir, relative); } function retrieveSourceMapURL(source) { diff --git a/test.js b/test.js index 81effcf..8acf5d0 100644 --- a/test.js +++ b/test.js @@ -6,6 +6,7 @@ var SourceMapGenerator = require('source-map').SourceMapGenerator; var child_process = require('child_process'); var assert = require('assert'); var fs = require('fs'); +var path = require('path'); function compareLines(actual, expected) { assert(actual.length >= expected.length, 'got ' + actual.length + ' lines but expected at least ' + expected.length + ' lines'); @@ -73,8 +74,31 @@ function createMultiLineSourceMapWithSourcesContent() { return sourceMap; } -function compareStackTrace(sourceMap, source, expected) { - // Check once with a separate source map +function createMultiLineSourceMapWithFileUrl() { + var sourceMap = new SourceMapGenerator({ + file: '.generated.js', + sourceRoot: fileURL('.') + }); + for (var i = 1; i <= 100; i++) { + sourceMap.addMapping({ + generated: { line: i, column: 0 }, + original: { line: 1000 + i, column: 99 + i }, + source: 'line' + i + '.js' + }); + } + return sourceMap; +} + + +function fileURL(file) { + file = path.resolve(file); + file = file.replace(/\\/g, '/'); + file = file[0] !== '/' ? '/' + file : file; + return encodeURI('file://' + file); +} + +function compareStackTrace(sourceMap, source, expected, useFileUrl) { + // Check once with a separate source map using a relative url fs.writeFileSync('.generated.js.map', sourceMap); fs.writeFileSync('.generated.js', 'exports.test = function() {' + source.join('\n') + '};//@ sourceMappingURL=.generated.js.map'); @@ -86,6 +110,19 @@ function compareStackTrace(sourceMap, source, expected) { } fs.unlinkSync('.generated.js'); fs.unlinkSync('.generated.js.map'); + + // Check again with a source map using a relative url + fs.writeFileSync('.generated.js.map', sourceMap); + fs.writeFileSync('.generated.js', 'exports.test = function() {' + + source.join('\n') + '};//@ sourceMappingURL=' + fileURL('.generated.js.map')); + try { + delete require.cache[require.resolve('./.generated')]; + require('./.generated').test(); + } catch (e) { + compareLines(e.stack.split('\n'), expected); + } + fs.unlinkSync('.generated.js'); + fs.unlinkSync('.generated.js.map'); // Check again with an inline source map (in a data URL) fs.writeFileSync('.generated.js', 'exports.test = function() {' + @@ -259,6 +296,15 @@ it('sourcesContent with data URL', function() { ]); }); +it('support file urls', function () { + compareStackTrace(createMultiLineSourceMapWithFileUrl(), [ + 'throw new Error("test");' + ], [ + 'Error: test', + /^ at Object\.exports\.test \(.*[\\/]line1\.js:1001:101\)$/ + ]); +}); + it('finds the last sourceMappingURL', function() { compareStackTrace(createMultiLineSourceMapWithSourcesContent(), [ '//# sourceMappingURL=missing.map.js', // NB: compareStackTrace adds another source mapping. @@ -472,7 +518,7 @@ it('allows code/comments after sourceMappingURL', function() { var source = [ 'throw new Error("test");' ]; var expected = [ 'Error: test', - /^ at Object\.exports\.test \(.*\/line1\.js:1001:101\)$/ + /^ at Object\.exports\.test \(.*[\\/]line1\.js:1001:101\)$/ ]; fs.writeFileSync('.generated.js', 'exports.test = function() {' + From 5836cc68f01bde128ca246b6bb90ef27c683e009 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Sat, 20 Feb 2016 14:58:08 -0800 Subject: [PATCH 3/8] Cleaned up url handling --- source-map-support.js | 104 ++++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 34 deletions(-) diff --git a/source-map-support.js b/source-map-support.js index 1c74a9c..670e3ac 100644 --- a/source-map-support.js +++ b/source-map-support.js @@ -73,8 +73,8 @@ retrieveFileHandlers.push(function(path) { // Otherwise, use the filesystem else { - if (isAbsoluteURL(path)) { - path = localURLPath(path); + if (isURI(path)) { + path = toPath(path); } var contents = fs.readFileSync(path, 'utf8'); } @@ -85,58 +85,94 @@ retrieveFileHandlers.push(function(path) { return fileContentsCache[path] = contents; }); -function isAbsoluteURL(file) { - if (/^\w+:\/\//i.test(file)) { - if (!isInBrowser()) { - var dir = path.dirname(file); - if (fs.existsSync(dir)) { - return false; - } - } - return true; - } - return false; +// Determines whether a file path is a URI using the following rules: +// - A path is a URI if it starts with an alpha character followed by +// one or more of either an alpha character, digit, '+', '-', or '-', +// followed by a colon. For example: +// http://tempuri.org/path - Web URI +// file://host/path - File URI for UNC path +// file:///c:/path - File URI for DOS path +// urn:custom - Other URI +// +// NOTE: A path is NOT a URI if it starts with a single alpha character +// and a colon is, instead it is treated as a DOS path. For example: +// c:/path - DOS path +// c:\path - DOS path +// +// - Any other sequence of characters is not considered a URI. +function isURI(file) { + return /^[a-z][a-z0-9+.\-]+:/i.test(file); } -function localURLPath(file) { - var parsed = url.parse(file); +// Tries to convert a URI to a local path. If the URI is a +// file URI (file://), it is converted into a local path format +// that NodeJS understands using the following rules: +// - A file URI with a host name is treated as a UNC path/NTFS +// long path: +// file://server/share -> //host/path +// file://?/UNC/server/share -> //?/UNC/server/share +// file://?/C:/long/path -> //?/C:/server/share +// +// - A file URI without a host name, whose first path segment is +// a single alpha character followed by either a colon (':') or +// pipe ('|') is treated as a rooted DOS path: +// file:///c:/path -> c:\path +// file:///c|/path -> c:\path +// +// - A file URI without a hostname that is not treated as a DOS +// path is treated as a rooted POSIX path: +// file:///etc/path -> /etc/path +// +// - Querystring (?) and fragments (#) are removed. +function toPath(uri) { + var parsed = url.parse(uri); if (parsed.protocol === 'file:') { - var local = decodeURIComponent(parsed.path); if (parsed.hostname) { - // SAMBA path - return '//' + parsed.hostname + local + // A file URI with a hostname is a UNC path. + return '\\\\' + parsed.hostname + decodeURIComponent(parsed.path).replace(/\//g, '\\'); } - else if (/^\/\w[:|]/.test(local)) { - // DOS path - return local.slice(1, 2) + ':' + local.slice(3).replace(/\//g, '\\'); + + if (!parsed.pathname && parsed.search) { + // A file URI without a pathname, but with a querystring are + // NTFS long path names. + var path = decodeURIComponent(parsed.search); + var match = /^(\\?[\\/][^?]*)/.exec(path); + if (match) { + return '\\\\' + match[1].replace(/\//g, '\\'); + } } - else { - // POSIX path - return local; + else if (parsed.pathname) { + var path = decodeURIComponent(parsed.pathname); + if (/^[\\/]\w[:|]/.test(path)) { + // DOS path + return path.slice(1, 2) + ':' + path.slice(3).replace(/\//g, '\\'); + } + else { + // POSIX path + return path.replace(/\\/g, '/'); + } } } - // Unhandled URL protocol, return it. - return file; + // Unhandled URI format. + return uri; } // Support URLs relative to a directory, but be careful about a protocol prefix // in case we are in the browser (i.e. directories may start with "http://") function supportRelativeURL(base, relative) { - if (!base) { + if (!base || isURI(relative)) { + // no base or relative is absolute URI return relative; } - if (isAbsoluteURL(base)) { + else if (isURI(base)) { // base is a url, use url to combine. return url.resolve(base, relative); } - if (isAbsoluteURL(relative)) { - // absolute url or DOS path - return relative; + else { + var dir = path.dirname(base); + return path.resolve(dir, relative); } - - var dir = path.dirname(base); - return path.resolve(dir, relative); } function retrieveSourceMapURL(source) { From 2bd6b19184958e267d17fb60e30cca6453e03d5f Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Sat, 20 Feb 2016 16:57:52 -0800 Subject: [PATCH 4/8] Removed NTFS long paths --- source-map-support.js | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/source-map-support.js b/source-map-support.js index 670e3ac..2413c44 100644 --- a/source-map-support.js +++ b/source-map-support.js @@ -89,10 +89,10 @@ retrieveFileHandlers.push(function(path) { // - A path is a URI if it starts with an alpha character followed by // one or more of either an alpha character, digit, '+', '-', or '-', // followed by a colon. For example: -// http://tempuri.org/path - Web URI -// file://host/path - File URI for UNC path -// file:///c:/path - File URI for DOS path -// urn:custom - Other URI +// http://tempuri.org/path - Web URI +// file://server/share - File URI for UNC path +// file:///c:/path - File URI for DOS path +// urn:custom - Other URI // // NOTE: A path is NOT a URI if it starts with a single alpha character // and a colon is, instead it is treated as a DOS path. For example: @@ -109,9 +109,7 @@ function isURI(file) { // that NodeJS understands using the following rules: // - A file URI with a host name is treated as a UNC path/NTFS // long path: -// file://server/share -> //host/path -// file://?/UNC/server/share -> //?/UNC/server/share -// file://?/C:/long/path -> //?/C:/server/share +// file://server/share -> \\host\path // // - A file URI without a host name, whose first path segment is // a single alpha character followed by either a colon (':') or @@ -132,16 +130,7 @@ function toPath(uri) { return '\\\\' + parsed.hostname + decodeURIComponent(parsed.path).replace(/\//g, '\\'); } - if (!parsed.pathname && parsed.search) { - // A file URI without a pathname, but with a querystring are - // NTFS long path names. - var path = decodeURIComponent(parsed.search); - var match = /^(\\?[\\/][^?]*)/.exec(path); - if (match) { - return '\\\\' + match[1].replace(/\//g, '\\'); - } - } - else if (parsed.pathname) { + if (parsed.pathname) { var path = decodeURIComponent(parsed.pathname); if (/^[\\/]\w[:|]/.test(path)) { // DOS path From 264f50cf2b99b6af211103ebb7e4fa05bf989015 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Sat, 20 Feb 2016 17:00:01 -0800 Subject: [PATCH 5/8] Restricted DOS paths to alpha drive letters. --- source-map-support.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source-map-support.js b/source-map-support.js index 2413c44..a28e185 100644 --- a/source-map-support.js +++ b/source-map-support.js @@ -132,7 +132,7 @@ function toPath(uri) { if (parsed.pathname) { var path = decodeURIComponent(parsed.pathname); - if (/^[\\/]\w[:|]/.test(path)) { + if (/^[\\/][a-z][:|]/.test(path)) { // DOS path return path.slice(1, 2) + ':' + path.slice(3).replace(/\//g, '\\'); } From 945109a68599bb8f8967a386794f83170dfb8662 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Sun, 21 Feb 2016 14:20:33 -0800 Subject: [PATCH 6/8] Updated .gitignore --- .gitignore | 2 ++ browser-test/script.js | 25 ------------------------- browser-test/script.map | 10 ---------- 3 files changed, 2 insertions(+), 35 deletions(-) delete mode 100644 browser-test/script.js delete mode 100644 browser-test/script.map diff --git a/.gitignore b/.gitignore index 19c622f..fc481ed 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ browserify-test/script.js browserify-test/script.map header-test/script.js header-test/script.map +browser-test/script.js +browser-test/script.map \ No newline at end of file diff --git a/browser-test/script.js b/browser-test/script.js deleted file mode 100644 index e16d414..0000000 --- a/browser-test/script.js +++ /dev/null @@ -1,25 +0,0 @@ -// Generated by CoffeeScript 1.7.1 -(function() { - var e, foo; - - sourceMapSupport.install(); - - foo = function() { - throw new Error('foo'); - }; - - try { - foo(); - } catch (_error) { - e = _error; - if (/\bscript\.coffee\b/.test(e.stack)) { - document.body.appendChild(document.createTextNode('Test passed')); - } else { - document.body.appendChild(document.createTextNode('Test failed')); - console.log(e.stack); - } - } - -}).call(this); - -//# sourceMappingURL=script.map diff --git a/browser-test/script.map b/browser-test/script.map deleted file mode 100644 index 8fcb11e..0000000 --- a/browser-test/script.map +++ /dev/null @@ -1,10 +0,0 @@ -{ - "version": 3, - "file": "script.js", - "sourceRoot": "..", - "sources": [ - "browser-test\\script.coffee" - ], - "names": [], - "mappings": ";AAAA;AAAA,MAAA,MAAA;;AAAA,EAAA,gBAAgB,CAAC,OAAjB,CAAA,CAAA,CAAA;;AAAA,EAEA,GAAA,GAAM,SAAA,GAAA;AAAG,UAAU,IAAA,KAAA,CAAM,KAAN,CAAV,CAAH;EAAA,CAFN,CAAA;;AAIA;AACE,IAAA,GAAA,CAAA,CAAA,CADF;GAAA,cAAA;AAGE,IADI,UACJ,CAAA;AAAA,IAAA,IAAG,oBAAoB,CAAC,IAArB,CAA0B,CAAC,CAAC,KAA5B,CAAH;AACE,MAAA,QAAQ,CAAC,IAAI,CAAC,WAAd,CAA0B,QAAQ,CAAC,cAAT,CAAwB,aAAxB,CAA1B,CAAA,CADF;KAAA,MAAA;AAGE,MAAA,QAAQ,CAAC,IAAI,CAAC,WAAd,CAA0B,QAAQ,CAAC,cAAT,CAAwB,aAAxB,CAA1B,CAAA,CAAA;AAAA,MACA,OAAO,CAAC,GAAR,CAAY,CAAC,CAAC,KAAd,CADA,CAHF;KAHF;GAJA;AAAA" -} \ No newline at end of file From 030590348aa14d81bba6f57546def0f303fa0941 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 7 Jun 2016 16:09:42 -0700 Subject: [PATCH 7/8] Fix case sensitivity for DOS paths. --- source-map-support.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source-map-support.js b/source-map-support.js index a28e185..a59dece 100644 --- a/source-map-support.js +++ b/source-map-support.js @@ -86,15 +86,15 @@ retrieveFileHandlers.push(function(path) { }); // Determines whether a file path is a URI using the following rules: -// - A path is a URI if it starts with an alpha character followed by -// one or more of either an alpha character, digit, '+', '-', or '-', +// - A path is a URI if it starts with an alpha character followed by +// one or more of either an alpha character, digit, '+', '-', or '-', // followed by a colon. For example: // http://tempuri.org/path - Web URI // file://server/share - File URI for UNC path // file:///c:/path - File URI for DOS path // urn:custom - Other URI // -// NOTE: A path is NOT a URI if it starts with a single alpha character +// NOTE: A path is NOT a URI if it starts with a single alpha character // and a colon is, instead it is treated as a DOS path. For example: // c:/path - DOS path // c:\path - DOS path @@ -104,7 +104,7 @@ function isURI(file) { return /^[a-z][a-z0-9+.\-]+:/i.test(file); } -// Tries to convert a URI to a local path. If the URI is a +// Tries to convert a URI to a local path. If the URI is a // file URI (file://), it is converted into a local path format // that NodeJS understands using the following rules: // - A file URI with a host name is treated as a UNC path/NTFS @@ -129,10 +129,10 @@ function toPath(uri) { // A file URI with a hostname is a UNC path. return '\\\\' + parsed.hostname + decodeURIComponent(parsed.path).replace(/\//g, '\\'); } - + if (parsed.pathname) { var path = decodeURIComponent(parsed.pathname); - if (/^[\\/][a-z][:|]/.test(path)) { + if (/^[\\/][a-z][:|]/i.test(path)) { // DOS path return path.slice(1, 2) + ':' + path.slice(3).replace(/\//g, '\\'); } From 9cf6863f537c227a2168baaffdaa047fced8949b Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 7 Jun 2016 16:15:43 -0700 Subject: [PATCH 8/8] Rename toPath to toLocalPath and export --- source-map-support.js | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/source-map-support.js b/source-map-support.js index a59dece..353189d 100644 --- a/source-map-support.js +++ b/source-map-support.js @@ -73,10 +73,7 @@ retrieveFileHandlers.push(function(path) { // Otherwise, use the filesystem else { - if (isURI(path)) { - path = toPath(path); - } - var contents = fs.readFileSync(path, 'utf8'); + var contents = fs.readFileSync(toLocalPath(path), 'utf8'); } } catch (e) { var contents = null; @@ -122,23 +119,25 @@ function isURI(file) { // file:///etc/path -> /etc/path // // - Querystring (?) and fragments (#) are removed. -function toPath(uri) { - var parsed = url.parse(uri); - if (parsed.protocol === 'file:') { - if (parsed.hostname) { - // A file URI with a hostname is a UNC path. - return '\\\\' + parsed.hostname + decodeURIComponent(parsed.path).replace(/\//g, '\\'); - } - - if (parsed.pathname) { - var path = decodeURIComponent(parsed.pathname); - if (/^[\\/][a-z][:|]/i.test(path)) { - // DOS path - return path.slice(1, 2) + ':' + path.slice(3).replace(/\//g, '\\'); +function toLocalPath(uri) { + if (isURI(uri)) { + var parsed = url.parse(uri); + if (parsed.protocol === 'file:') { + if (parsed.hostname) { + // A file URI with a hostname is a UNC path. + return '\\\\' + parsed.hostname + decodeURIComponent(parsed.path).replace(/\//g, '\\'); } - else { - // POSIX path - return path.replace(/\\/g, '/'); + + if (parsed.pathname) { + var path = decodeURIComponent(parsed.pathname); + if (/^[\\/][a-z][:|]/i.test(path)) { + // DOS path + return path.slice(1, 2) + ':' + path.slice(3).replace(/\//g, '\\'); + } + else { + // POSIX path + return path.replace(/\\/g, '/'); + } } } } @@ -493,6 +492,7 @@ exports.wrapCallSite = wrapCallSite; exports.getErrorSource = getErrorSource; exports.mapSourcePosition = mapSourcePosition; exports.retrieveSourceMap = retrieveSourceMap; +exports.toLocalPath = toLocalPath; exports.install = function(options) { options = options || {};