зеркало из https://github.com/mozilla/gecko-dev.git
Backout a69d60d90110 (bug 772119) for bustage
This commit is contained in:
Родитель
adbaf91a38
Коммит
2d0b4a0736
|
@ -1062,7 +1062,6 @@ pref("devtools.debugger.remote-host", "localhost");
|
|||
pref("devtools.debugger.remote-autoconnect", false);
|
||||
pref("devtools.debugger.remote-connection-retries", 3);
|
||||
pref("devtools.debugger.remote-timeout", 20000);
|
||||
pref("devtools.debugger.source-maps-enabled", false);
|
||||
|
||||
// The default Debugger UI settings
|
||||
pref("devtools.debugger.ui.win-x", 0);
|
||||
|
|
|
@ -262,8 +262,6 @@ let DebuggerController = {
|
|||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
}, {
|
||||
useSourceMaps: Services.prefs.getBoolPref("devtools.debugger.source-maps-enabled")
|
||||
});
|
||||
});
|
||||
},
|
||||
|
@ -1097,7 +1095,7 @@ SourceScripts.prototype = {
|
|||
*/
|
||||
_onSourcesAdded: function SS__onSourcesAdded(aResponse) {
|
||||
if (aResponse.error) {
|
||||
Cu.reportError(new Error("Error getting sources: " + aResponse.message));
|
||||
Cu.reportError("Error getting sources: " + aResponse.message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,6 @@ MOCHITEST_BROWSER_TESTS = \
|
|||
browser_dbg_bfcache.js \
|
||||
browser_dbg_progress-listener-bug.js \
|
||||
browser_dbg_chrome-debugging.js \
|
||||
browser_dbg_source_maps-01.js \
|
||||
head.js \
|
||||
helpers.js \
|
||||
$(NULL)
|
||||
|
@ -130,10 +129,6 @@ MOCHITEST_BROWSER_PAGES = \
|
|||
test-function-search-01.js \
|
||||
test-function-search-02.js \
|
||||
test-function-search-03.js \
|
||||
binary_search.html \
|
||||
binary_search.coffee \
|
||||
binary_search.js \
|
||||
binary_search.map \
|
||||
$(NULL)
|
||||
|
||||
MOCHITEST_BROWSER_FILES_PARTS = MOCHITEST_BROWSER_TESTS MOCHITEST_BROWSER_PAGES
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
# Uses a binary search algorithm to locate a value in the specified array.
|
||||
window.binary_search = (items, value) ->
|
||||
|
||||
start = 0
|
||||
stop = items.length - 1
|
||||
pivot = Math.floor (start + stop) / 2
|
||||
|
||||
while items[pivot] isnt value and start < stop
|
||||
|
||||
# Adjust the search area.
|
||||
stop = pivot - 1 if value < items[pivot]
|
||||
start = pivot + 1 if value > items[pivot]
|
||||
|
||||
# Recalculate the pivot.
|
||||
pivot = Math.floor (stop + start) / 2
|
||||
|
||||
# Make sure we've found the correct value.
|
||||
if items[pivot] is value then pivot else -1
|
|
@ -1,12 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'/>
|
||||
<title>Browser Debugger Source Map Test</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript" src="binary_search.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -1,30 +0,0 @@
|
|||
// Generated by CoffeeScript 1.6.1
|
||||
(function() {
|
||||
|
||||
window.binary_search = function(items, value) {
|
||||
var pivot, start, stop;
|
||||
start = 0;
|
||||
stop = items.length - 1;
|
||||
pivot = Math.floor((start + stop) / 2);
|
||||
while (items[pivot] !== value && start < stop) {
|
||||
if (value < items[pivot]) {
|
||||
stop = pivot - 1;
|
||||
}
|
||||
if (value > items[pivot]) {
|
||||
start = pivot + 1;
|
||||
}
|
||||
pivot = Math.floor((stop + start) / 2);
|
||||
}
|
||||
if (items[pivot] === value) {
|
||||
return pivot;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
// TODO bug 849069: this should just be "binary_search.map", not a full path.
|
||||
/*
|
||||
//@ sourceMappingURL=http://example.com/browser/browser/devtools/debugger/test/binary_search.map
|
||||
*/
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "binary_search.js",
|
||||
"sources": [
|
||||
"http://example.com/browser/browser/devtools/debugger/test/binary_search.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": ";AACA;CAAA;CAAA,CAAA,CAAuB,EAAA,CAAjB,GAAkB,IAAxB;CAEE,OAAA,UAAA;CAAA,EAAQ,CAAR,CAAA;CAAA,EACQ,CAAR,CAAa,CAAL;CADR,EAEQ,CAAR,CAAA;CAEA,EAA0C,CAAR,CAAtB,MAAN;CAGJ,EAA6B,CAAR,CAAA,CAArB;CAAA,EAAQ,CAAR,CAAQ,GAAR;QAAA;CACA,EAA6B,CAAR,CAAA,CAArB;CAAA,EAAQ,EAAR,GAAA;QADA;CAAA,EAIQ,CAAI,CAAZ,CAAA;CAXF,IAIA;CAUA,GAAA,CAAS;CAAT,YAA8B;MAA9B;AAA0C,CAAD,YAAA;MAhBpB;CAAvB,EAAuB;CAAvB"
|
||||
}
|
|
@ -27,22 +27,19 @@ function test()
|
|||
gDebugger = gPane.panelWin;
|
||||
resumed = true;
|
||||
|
||||
gDebugger.addEventListener("Debugger:SourceShown", onSourceShown);
|
||||
gDebugger.addEventListener("Debugger:SourceShown", onScriptShown);
|
||||
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded",
|
||||
onFramesAdded);
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
framesAdded = true;
|
||||
executeSoon(startTest);
|
||||
});
|
||||
|
||||
executeSoon(function() {
|
||||
gDebuggee.firstCall();
|
||||
});
|
||||
});
|
||||
|
||||
function onFramesAdded(aEvent) {
|
||||
framesAdded = true;
|
||||
executeSoon(startTest);
|
||||
}
|
||||
|
||||
function onSourceShown(aEvent) {
|
||||
function onScriptShown(aEvent) {
|
||||
scriptShown = aEvent.detail.url.indexOf("-02.js") != -1;
|
||||
executeSoon(startTest);
|
||||
}
|
||||
|
@ -51,8 +48,8 @@ function test()
|
|||
{
|
||||
if (scriptShown && framesAdded && resumed && !testStarted) {
|
||||
testStarted = true;
|
||||
gDebugger.removeEventListener("Debugger:SourceShown", onSourceShown);
|
||||
executeSoon(performTest);
|
||||
gDebugger.removeEventListener("Debugger:SourceShown", onScriptShown);
|
||||
Services.tm.currentThread.dispatch({ run: performTest }, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,7 +109,6 @@ function test()
|
|||
}
|
||||
|
||||
executeSoon(function() {
|
||||
dump("\n\n\n\n\n\n\n\n\n\n\n" + gDebugger.editor.getText() + "\n\n\n\n\n\n\n\n");
|
||||
contextMenu.hidePopup();
|
||||
closeDebuggerAndFinish();
|
||||
});
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test that we can set breakpoints and step through source mapped coffee
|
||||
* script.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "binary_search.html";
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
let resumed = false;
|
||||
let testStarted = false;
|
||||
|
||||
Services.prefs.setBoolPref("devtools.debugger.source-maps-enabled", true);
|
||||
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
resumed = true;
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.panelWin;
|
||||
|
||||
gDebugger.addEventListener("Debugger:SourceShown", function _onSourceShown(aEvent) {
|
||||
gDebugger.removeEventListener("Debugger:SourceShown", _onSourceShown);
|
||||
ok(aEvent.detail.url.indexOf(".coffee") != -1,
|
||||
"The debugger should show the source mapped coffee script file.");
|
||||
ok(gDebugger.editor.getText().search(/isnt/) != -1,
|
||||
"The debugger's editor should have the coffee script source displayed.");
|
||||
|
||||
testSetBreakpoint();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testSetBreakpoint() {
|
||||
let { activeThread } = gDebugger.DebuggerController;
|
||||
activeThread.interrupt(function (aResponse) {
|
||||
activeThread.setBreakpoint({
|
||||
url: EXAMPLE_URL + "binary_search.coffee",
|
||||
line: 5
|
||||
}, function (aResponse, bpClient) {
|
||||
ok(!aResponse.error,
|
||||
"Should be able to set a breakpoint in a coffee script file.");
|
||||
testSetBreakpointBlankLine();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testSetBreakpointBlankLine() {
|
||||
let { activeThread } = gDebugger.DebuggerController;
|
||||
activeThread.setBreakpoint({
|
||||
url: EXAMPLE_URL + "binary_search.coffee",
|
||||
line: 3
|
||||
}, function (aResponse, bpClient) {
|
||||
ok(aResponse.actualLocation,
|
||||
"Because 3 is empty, we should have an actualLocation");
|
||||
is(aResponse.actualLocation.url, EXAMPLE_URL + "binary_search.coffee",
|
||||
"actualLocation.url should be source mapped to the coffee file");
|
||||
is(aResponse.actualLocation.line, 2,
|
||||
"actualLocation.line should be source mapped back to 2");
|
||||
testHitBreakpoint();
|
||||
});
|
||||
}
|
||||
|
||||
function testHitBreakpoint() {
|
||||
let { activeThread } = gDebugger.DebuggerController;
|
||||
activeThread.resume(function (aResponse) {
|
||||
ok(!aResponse.error, "Shouldn't get an error resuming");
|
||||
is(aResponse.type, "resumed", "Type should be 'resumed'");
|
||||
|
||||
activeThread.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||
is(aPacket.type, "paused",
|
||||
"We should now be paused again");
|
||||
is(aPacket.why.type, "breakpoint",
|
||||
"and the reason we should be paused is because we hit a breakpoint");
|
||||
|
||||
// Check that we stopped at the right place, by making sure that the
|
||||
// environment is in the state that we expect.
|
||||
is(aPacket.frame.environment.bindings.variables.start.value, 0,
|
||||
"'start' is 0");
|
||||
is(aPacket.frame.environment.bindings.variables.stop.value.type, "undefined",
|
||||
"'stop' hasn't been assigned to yet");
|
||||
is(aPacket.frame.environment.bindings.variables.pivot.value.type, "undefined",
|
||||
"'pivot' hasn't been assigned to yet");
|
||||
|
||||
waitForCaretPos(4, testStepping);
|
||||
});
|
||||
|
||||
// This will cause the breakpoint to be hit, and put us back in the paused
|
||||
// state.
|
||||
executeSoon(function() {
|
||||
gDebuggee.binary_search([0, 2, 3, 5, 7, 10], 5);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testStepping() {
|
||||
let { activeThread } = gDebugger.DebuggerController;
|
||||
activeThread.resume(function (aResponse) {
|
||||
ok(!aResponse.error, "Shouldn't get an error resuming");
|
||||
is(aResponse.type, "resumed", "Type should be 'resumed'");
|
||||
|
||||
// After stepping, we will pause again, so listen for that.
|
||||
activeThread.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||
|
||||
// Check that we stopped at the right place, by making sure that the
|
||||
// environment is in the state that we expect.
|
||||
is(aPacket.frame.environment.bindings.variables.start.value, 0,
|
||||
"'start' is 0");
|
||||
is(aPacket.frame.environment.bindings.variables.stop.value, 5,
|
||||
"'stop' hasn't been assigned to yet");
|
||||
is(aPacket.frame.environment.bindings.variables.pivot.value.type, "undefined",
|
||||
"'pivot' hasn't been assigned to yet");
|
||||
|
||||
waitForCaretPos(5, closeDebuggerAndFinish);
|
||||
});
|
||||
}, {
|
||||
type: "step"
|
||||
});
|
||||
}
|
||||
|
||||
function waitForCaretPos(number, callback)
|
||||
{
|
||||
// Poll every few milliseconds until the source editor line is active.
|
||||
let count = 0;
|
||||
let intervalID = window.setInterval(function() {
|
||||
info("count: " + count + " ");
|
||||
if (++count > 50) {
|
||||
ok(false, "Timed out while polling for the line.");
|
||||
window.clearInterval(intervalID);
|
||||
return closeDebuggerAndFinish();
|
||||
}
|
||||
if (gDebugger.DebuggerView.editor.getCaretPosition().line != number) {
|
||||
return;
|
||||
}
|
||||
// We got the source editor at the expected line, it's safe to callback.
|
||||
window.clearInterval(intervalID);
|
||||
callback();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.setBoolPref("devtools.debugger.source-maps-enabled", false);
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gDebugger = null;
|
||||
});
|
|
@ -322,10 +322,7 @@ DebuggerClient.prototype = {
|
|||
*/
|
||||
attachTab: function DC_attachTab(aTabActor, aOnResponse) {
|
||||
let self = this;
|
||||
let packet = {
|
||||
to: aTabActor,
|
||||
type: "attach"
|
||||
};
|
||||
let packet = { to: aTabActor, type: "attach" };
|
||||
this.request(packet, function(aResponse) {
|
||||
let tabClient;
|
||||
if (!aResponse.error) {
|
||||
|
@ -375,17 +372,10 @@ DebuggerClient.prototype = {
|
|||
* @param function aOnResponse
|
||||
* Called with the response packet and a ThreadClient
|
||||
* (which will be undefined on error).
|
||||
* @param object aOptions
|
||||
* Configuration options.
|
||||
* - useSourceMaps: whether to use source maps or not.
|
||||
*/
|
||||
attachThread: function DC_attachThread(aThreadActor, aOnResponse, aOptions={}) {
|
||||
attachThread: function DC_attachThread(aThreadActor, aOnResponse) {
|
||||
let self = this;
|
||||
let packet = {
|
||||
to: aThreadActor,
|
||||
type: "attach",
|
||||
options: aOptions
|
||||
};
|
||||
let packet = { to: aThreadActor, type: "attach" };
|
||||
this.request(packet, function(aResponse) {
|
||||
if (!aResponse.error) {
|
||||
var threadClient = new ThreadClient(self, aThreadActor);
|
||||
|
@ -443,7 +433,7 @@ DebuggerClient.prototype = {
|
|||
*/
|
||||
_sendRequests: function DC_sendRequests() {
|
||||
let self = this;
|
||||
this._pendingRequests = this._pendingRequests.filter(function (request) {
|
||||
this._pendingRequests = this._pendingRequests.filter(function(request) {
|
||||
if (request.to in self._activeRequests) {
|
||||
return true;
|
||||
}
|
||||
|
@ -480,53 +470,55 @@ DebuggerClient.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!aPacket.from) {
|
||||
let msg = "Server did not specify an actor, dropping packet: " +
|
||||
JSON.stringify(aPacket);
|
||||
Cu.reportError(msg);
|
||||
dumpn(msg);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (!aPacket.from) {
|
||||
let msg = "Server did not specify an actor, dropping packet: " +
|
||||
JSON.stringify(aPacket);
|
||||
Cu.reportError(msg);
|
||||
dumpn(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
let onResponse;
|
||||
// Don't count unsolicited notifications or pauses as responses.
|
||||
if (aPacket.from in this._activeRequests &&
|
||||
!(aPacket.type in UnsolicitedNotifications) &&
|
||||
!(aPacket.type == ThreadStateTypes.paused &&
|
||||
aPacket.why.type in UnsolicitedPauses)) {
|
||||
onResponse = this._activeRequests[aPacket.from].onResponse;
|
||||
delete this._activeRequests[aPacket.from];
|
||||
}
|
||||
let onResponse;
|
||||
// Don't count unsolicited notifications or pauses as responses.
|
||||
if (aPacket.from in this._activeRequests &&
|
||||
!(aPacket.type in UnsolicitedNotifications) &&
|
||||
!(aPacket.type == ThreadStateTypes.paused &&
|
||||
aPacket.why.type in UnsolicitedPauses)) {
|
||||
onResponse = this._activeRequests[aPacket.from].onResponse;
|
||||
delete this._activeRequests[aPacket.from];
|
||||
}
|
||||
|
||||
// Packets that indicate thread state changes get special treatment.
|
||||
if (aPacket.type in ThreadStateTypes &&
|
||||
aPacket.from in this._threadClients) {
|
||||
this._threadClients[aPacket.from]._onThreadState(aPacket);
|
||||
}
|
||||
// On navigation the server resumes, so the client must resume as well.
|
||||
// We achieve that by generating a fake resumption packet that triggers
|
||||
// the client's thread state change listeners.
|
||||
if (this.activeThread &&
|
||||
aPacket.type == UnsolicitedNotifications.tabNavigated &&
|
||||
aPacket.from in this._tabClients) {
|
||||
let resumption = { from: this.activeThread._actor, type: "resumed" };
|
||||
this.activeThread._onThreadState(resumption);
|
||||
}
|
||||
// Only try to notify listeners on events, not responses to requests
|
||||
// that lack a packet type.
|
||||
if (aPacket.type) {
|
||||
this.notify(aPacket.type, aPacket);
|
||||
}
|
||||
// Packets that indicate thread state changes get special treatment.
|
||||
if (aPacket.type in ThreadStateTypes &&
|
||||
aPacket.from in this._threadClients) {
|
||||
this._threadClients[aPacket.from]._onThreadState(aPacket);
|
||||
}
|
||||
// On navigation the server resumes, so the client must resume as well.
|
||||
// We achieve that by generating a fake resumption packet that triggers
|
||||
// the client's thread state change listeners.
|
||||
if (this.activeThread &&
|
||||
aPacket.type == UnsolicitedNotifications.tabNavigated &&
|
||||
aPacket.from in this._tabClients) {
|
||||
let resumption = { from: this.activeThread._actor, type: "resumed" };
|
||||
this.activeThread._onThreadState(resumption);
|
||||
}
|
||||
// Only try to notify listeners on events, not responses to requests
|
||||
// that lack a packet type.
|
||||
if (aPacket.type) {
|
||||
this.notify(aPacket.type, aPacket);
|
||||
}
|
||||
|
||||
if (onResponse) {
|
||||
onResponse(aPacket);
|
||||
if (onResponse) {
|
||||
onResponse(aPacket);
|
||||
}
|
||||
} catch(ex) {
|
||||
dumpn("Error handling response: " + ex + " - stack:\n" + ex.stack);
|
||||
Cu.reportError(ex.message + "\n" + ex.stack);
|
||||
}
|
||||
|
||||
this._sendRequests();
|
||||
}.bind(this), function (ex) {
|
||||
dumpn("Error handling response: " + ex + " - stack:\n" + ex.stack);
|
||||
Cu.reportError(ex.message + "\n" + ex.stack);
|
||||
});
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,6 +30,7 @@ function ThreadActor(aHooks, aGlobal)
|
|||
this._frameActors = [];
|
||||
this._environmentActors = [];
|
||||
this._hooks = aHooks;
|
||||
this._sources = {};
|
||||
this.global = aGlobal;
|
||||
|
||||
// A cache of prototype chains for objects that have received a
|
||||
|
@ -45,11 +46,6 @@ function ThreadActor(aHooks, aGlobal)
|
|||
|
||||
this.findGlobals = this.globalManager.findGlobals.bind(this);
|
||||
this.onNewGlobal = this.globalManager.onNewGlobal.bind(this);
|
||||
this.onNewSource = this.onNewSource.bind(this);
|
||||
|
||||
this._options = {
|
||||
useSourceMaps: false
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,21 +73,13 @@ ThreadActor.prototype = {
|
|||
return this._threadLifetimePool;
|
||||
},
|
||||
|
||||
get sources() {
|
||||
if (!this._sources) {
|
||||
this._sources = new ThreadSources(this, this._options.useSourceMaps,
|
||||
this._allowSource, this.onNewSource);
|
||||
}
|
||||
return this._sources;
|
||||
},
|
||||
|
||||
clearDebuggees: function TA_clearDebuggees() {
|
||||
if (this.dbg) {
|
||||
this.dbg.removeAllDebuggees();
|
||||
}
|
||||
this.conn.removeActorPool(this._threadLifetimePool || undefined);
|
||||
this._threadLifetimePool = null;
|
||||
this._sources = null;
|
||||
this._sources = {};
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -214,14 +202,11 @@ ThreadActor.prototype = {
|
|||
|
||||
this._state = "attached";
|
||||
|
||||
update(this._options, aRequest.options || {});
|
||||
|
||||
if (!this.dbg) {
|
||||
this._initDebugger();
|
||||
}
|
||||
this.findGlobals();
|
||||
this.dbg.enabled = true;
|
||||
|
||||
try {
|
||||
// Put ourselves in the paused state.
|
||||
let packet = this._paused();
|
||||
|
@ -237,20 +222,19 @@ ThreadActor.prototype = {
|
|||
|
||||
// Start a nested event loop.
|
||||
this._nest();
|
||||
|
||||
// We already sent a response to this request, don't send one
|
||||
// now.
|
||||
return null;
|
||||
} catch (e) {
|
||||
reportError(e);
|
||||
} catch(e) {
|
||||
Cu.reportError(e);
|
||||
return { error: "notAttached", message: e.toString() };
|
||||
}
|
||||
},
|
||||
|
||||
onDetach: function TA_onDetach(aRequest) {
|
||||
this.disconnect();
|
||||
return {
|
||||
type: "detached"
|
||||
};
|
||||
return { type: "detached" };
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -261,19 +245,15 @@ ThreadActor.prototype = {
|
|||
* The newest debuggee frame in the stack.
|
||||
* @param object aReason
|
||||
* An object with a 'type' property containing the reason for the pause.
|
||||
* @param function onPacket
|
||||
* Hook to modify the packet before it is sent. Feel free to return a
|
||||
* promise.
|
||||
*/
|
||||
_pauseAndRespond: function TA__pauseAndRespond(aFrame, aReason,
|
||||
onPacket=function (k) k) {
|
||||
_pauseAndRespond: function TA__pauseAndRespond(aFrame, aReason) {
|
||||
try {
|
||||
let packet = this._paused(aFrame);
|
||||
if (!packet) {
|
||||
return undefined;
|
||||
}
|
||||
packet.why = aReason;
|
||||
resolve(onPacket(packet)).then(this.conn.send.bind(this.conn));
|
||||
this.conn.send(packet);
|
||||
return this._nest();
|
||||
} catch(e) {
|
||||
let msg = "Got an exception during TA__pauseAndRespond: " + e +
|
||||
|
@ -447,23 +427,14 @@ ThreadActor.prototype = {
|
|||
// Return request.count frames, or all remaining
|
||||
// frames if count is not defined.
|
||||
let frames = [];
|
||||
let promises = [];
|
||||
for (; frame && (!count || i < (start + count)); i++, frame=frame.older) {
|
||||
for (; frame && (!count || i < (start + count)); i++) {
|
||||
let form = this._createFrameActor(frame).form();
|
||||
form.depth = i;
|
||||
frames.push(form);
|
||||
|
||||
let promise = this.sources.getOriginalLocation(form.where.url,
|
||||
form.where.line)
|
||||
.then(function (aOrigLocation) {
|
||||
form.where = aOrigLocation;
|
||||
});
|
||||
promises.push(promise);
|
||||
frame = frame.older;
|
||||
}
|
||||
|
||||
return Promise.all(promises).then(function () {
|
||||
return { frames: frames };
|
||||
});
|
||||
return { frames: frames };
|
||||
},
|
||||
|
||||
onReleaseMany: function TA_onReleaseMany(aRequest) {
|
||||
|
@ -496,58 +467,25 @@ ThreadActor.prototype = {
|
|||
message: "Breakpoints can only be set while the debuggee is paused."};
|
||||
}
|
||||
|
||||
// XXX: `originalColumn` is never used. See bug 827639.
|
||||
let { url: originalSource,
|
||||
line: originalLine,
|
||||
column: originalColumn } = aRequest.location;
|
||||
let location = aRequest.location;
|
||||
let line = location.line;
|
||||
if (this.dbg.findScripts({ url: location.url }).length == 0 || line < 0) {
|
||||
return { error: "noScript" };
|
||||
}
|
||||
|
||||
let locationPromise = this.sources.getGeneratedLocation(originalSource,
|
||||
originalLine)
|
||||
return locationPromise.then(function (aLocation) {
|
||||
let line = aLocation.line;
|
||||
if (this.dbg.findScripts({ url: aLocation.url }).length == 0 || line < 0) {
|
||||
return { error: "noScript" };
|
||||
}
|
||||
// Add the breakpoint to the store for later reuse, in case it belongs to a
|
||||
// script that hasn't appeared yet.
|
||||
if (!this._breakpointStore[location.url]) {
|
||||
this._breakpointStore[location.url] = [];
|
||||
}
|
||||
let scriptBreakpoints = this._breakpointStore[location.url];
|
||||
scriptBreakpoints[line] = {
|
||||
url: location.url,
|
||||
line: line,
|
||||
column: location.column
|
||||
};
|
||||
|
||||
// Add the breakpoint to the store for later reuse, in case it belongs to a
|
||||
// script that hasn't appeared yet.
|
||||
if (!this._breakpointStore[aLocation.url]) {
|
||||
this._breakpointStore[aLocation.url] = [];
|
||||
}
|
||||
let scriptBreakpoints = this._breakpointStore[aLocation.url];
|
||||
scriptBreakpoints[line] = {
|
||||
url: aLocation.url,
|
||||
line: line,
|
||||
column: aLocation.column
|
||||
};
|
||||
|
||||
let response = this._setBreakpoint(aLocation);
|
||||
// If the original location of our generated location is different from
|
||||
// the original location we attempted to set the breakpoint on, we will
|
||||
// need to know so that we can set actualLocation on the response.
|
||||
let originalLocation = this.sources.getOriginalLocation(aLocation.url,
|
||||
aLocation.line);
|
||||
|
||||
return Promise.all(response, originalLocation)
|
||||
.then(function ([aResponse, {url, line}]) {
|
||||
if (aResponse.actualLocation) {
|
||||
let actualOrigLocation = this.sources.getOriginalLocation(
|
||||
aResponse.actualLocation.url, aResponse.actualLocation.line);
|
||||
return actualOrigLocation.then(function ({ url, line }) {
|
||||
if (url !== originalSource || line !== originalLine) {
|
||||
aResponse.actualLocation = { url: url, line: line };
|
||||
}
|
||||
return aResponse;
|
||||
});
|
||||
}
|
||||
|
||||
if (url !== originalSource || line !== originalLine) {
|
||||
aResponse.actualLocation = { url: url, line: line };
|
||||
}
|
||||
|
||||
return aResponse;
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
return this._setBreakpoint(location);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -658,16 +596,17 @@ ThreadActor.prototype = {
|
|||
* Get the script and source lists from the debugger.
|
||||
*/
|
||||
_discoverScriptsAndSources: function TA__discoverScriptsAndSources() {
|
||||
return Promise.all([this._addScript(s)
|
||||
for (s of this.dbg.findScripts())]);
|
||||
for (let s of this.dbg.findScripts()) {
|
||||
this._addScript(s);
|
||||
}
|
||||
},
|
||||
|
||||
onSources: function TA_onSources(aRequest) {
|
||||
return this._discoverScriptsAndSources().then(function () {
|
||||
return {
|
||||
sources: [s.form() for (s of this.sources.iter())]
|
||||
};
|
||||
}.bind(this));
|
||||
this._discoverScriptsAndSources();
|
||||
let urls = Object.getOwnPropertyNames(this._sources);
|
||||
return {
|
||||
sources: [this._getSource(url).form() for (url of urls)]
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -704,8 +643,8 @@ ThreadActor.prototype = {
|
|||
// We already sent a response to this request, don't send one
|
||||
// now.
|
||||
return null;
|
||||
} catch (e) {
|
||||
reportError(e);
|
||||
} catch(e) {
|
||||
Cu.reportError(e);
|
||||
return { error: "notInterrupted", message: e.toString() };
|
||||
}
|
||||
},
|
||||
|
@ -776,6 +715,7 @@ ThreadActor.prototype = {
|
|||
if (aFrame) {
|
||||
packet.frame = this._createFrameActor(aFrame).form();
|
||||
}
|
||||
|
||||
if (poppedFrames) {
|
||||
packet.poppedFrames = poppedFrames;
|
||||
}
|
||||
|
@ -1078,9 +1018,8 @@ ThreadActor.prototype = {
|
|||
* Create a source grip for the given script.
|
||||
*/
|
||||
sourceGrip: function TA_sourceGrip(aScript) {
|
||||
// TODO bug 637572: Once we have Debugger.Source, this should be replaced
|
||||
// with a weakmap mapping Debugger.Source instances to SourceActor
|
||||
// instances.
|
||||
// TODO: Once we have Debugger.Source, this should be replaced with a
|
||||
// weakmap mapping Debugger.Source instances to SourceActor instances.
|
||||
if (!this.threadLifetimePool.sourceActors) {
|
||||
this.threadLifetimePool.sourceActors = {};
|
||||
}
|
||||
|
@ -1140,7 +1079,7 @@ ThreadActor.prototype = {
|
|||
exception: this.createValueGrip(aValue) };
|
||||
this.conn.send(packet);
|
||||
return this._nest();
|
||||
} catch (e) {
|
||||
} catch(e) {
|
||||
Cu.reportError("Got an exception during TA_onExceptionUnwind: " + e +
|
||||
": " + e.stack);
|
||||
return undefined;
|
||||
|
@ -1160,14 +1099,6 @@ ThreadActor.prototype = {
|
|||
this._addScript(aScript);
|
||||
},
|
||||
|
||||
onNewSource: function TA_onNewSource(aSource) {
|
||||
this.conn.send({
|
||||
from: this.actorID,
|
||||
type: "newSource",
|
||||
source: aSource.form()
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if scripts from the provided source URL are allowed to be stored in
|
||||
* the cache.
|
||||
|
@ -1176,7 +1107,7 @@ ThreadActor.prototype = {
|
|||
* The url of the script's source that will be stored.
|
||||
* @returns true, if the script can be added, false otherwise.
|
||||
*/
|
||||
_allowSource: function TA__allowSource(aSourceUrl) {
|
||||
_allowSource: function TA__allowScript(aSourceUrl) {
|
||||
// Ignore anything we don't have a URL for (eval scripts, for example).
|
||||
if (!aSourceUrl)
|
||||
return false;
|
||||
|
@ -1200,30 +1131,28 @@ ThreadActor.prototype = {
|
|||
*/
|
||||
_addScript: function TA__addScript(aScript) {
|
||||
if (!this._allowSource(aScript.url)) {
|
||||
return resolve(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO bug 637572: we should be dealing with sources directly, not
|
||||
// inferring them through scripts.
|
||||
return this.sources.sourcesForScript(aScript).then(function () {
|
||||
this._addSource(aScript.url);
|
||||
|
||||
// Set any stored breakpoints.
|
||||
let existing = this._breakpointStore[aScript.url];
|
||||
if (existing) {
|
||||
let endLine = aScript.startLine + aScript.lineCount - 1;
|
||||
// Iterate over the lines backwards, so that sliding breakpoints don't
|
||||
// affect the loop.
|
||||
for (let line = existing.length - 1; line >= 0; line--) {
|
||||
let bp = existing[line];
|
||||
// Limit search to the line numbers contained in the new script.
|
||||
if (bp && line >= aScript.startLine && line <= endLine) {
|
||||
this._setBreakpoint(bp);
|
||||
}
|
||||
// Set any stored breakpoints.
|
||||
let existing = this._breakpointStore[aScript.url];
|
||||
if (existing) {
|
||||
let endLine = aScript.startLine + aScript.lineCount - 1;
|
||||
// Iterate over the lines backwards, so that sliding breakpoints don't
|
||||
// affect the loop.
|
||||
for (let line = existing.length - 1; line >= 0; line--) {
|
||||
let bp = existing[line];
|
||||
// Limit search to the line numbers contained in the new script.
|
||||
if (bp && line >= aScript.startLine && line <= endLine) {
|
||||
this._setBreakpoint(bp);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}.bind(this));
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1271,6 +1200,48 @@ ThreadActor.prototype = {
|
|||
return retval;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a source to the current set of sources.
|
||||
*
|
||||
* Right now this takes an url, but in the future it should
|
||||
* take a Debugger.Source.
|
||||
*
|
||||
* @param string the source URL.
|
||||
* @returns a SourceActor representing the source.
|
||||
*/
|
||||
_addSource: function TA__addSource(aURL) {
|
||||
if (!this._allowSource(aURL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aURL in this._sources) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let actor = new SourceActor(aURL, this);
|
||||
this.threadLifetimePool.addActor(actor);
|
||||
this._sources[aURL] = actor;
|
||||
|
||||
this.conn.send({
|
||||
from: this.actorID,
|
||||
type: "newSource",
|
||||
source: actor.form()
|
||||
});
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the source actor for the given URL.
|
||||
*/
|
||||
_getSource: function TA__getSource(aUrl) {
|
||||
let source = this._sources[aUrl];
|
||||
if (!source) {
|
||||
throw new Error("No source for '" + aUrl + "'");
|
||||
}
|
||||
return source;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
ThreadActor.prototype.requestTypes = {
|
||||
|
@ -1377,7 +1348,6 @@ SourceActor.prototype = {
|
|||
actorPrefix: "source",
|
||||
|
||||
get threadActor() { return this._threadActor; },
|
||||
get url() { return this._url; },
|
||||
|
||||
form: function SA_form() {
|
||||
return {
|
||||
|
@ -1397,9 +1367,10 @@ SourceActor.prototype = {
|
|||
* Handler for the "source" packet.
|
||||
*/
|
||||
onSource: function SA_onSource(aRequest) {
|
||||
return fetch(this._url)
|
||||
return this
|
||||
._loadSource()
|
||||
.then(function(aSource) {
|
||||
return this.threadActor.createValueGrip(
|
||||
return this._threadActor.createValueGrip(
|
||||
aSource, this.threadActor.threadLifetimePool);
|
||||
}.bind(this))
|
||||
.then(function (aSourceGrip) {
|
||||
|
@ -1408,17 +1379,121 @@ SourceActor.prototype = {
|
|||
source: aSourceGrip
|
||||
};
|
||||
}.bind(this), function (aError) {
|
||||
let msg = "Got an exception during SA_onSource: " + aError +
|
||||
"\n" + aError.stack;
|
||||
Cu.reportError(msg);
|
||||
dumpn(msg);
|
||||
return {
|
||||
"from": this.actorID,
|
||||
"error": "loadSourceError",
|
||||
"message": "Could not load the source for " + this._url + "."
|
||||
};
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a given string, encoded in a given character set, to unicode.
|
||||
* @param string aString
|
||||
* A string.
|
||||
* @param string aCharset
|
||||
* A character set.
|
||||
* @return string
|
||||
* A unicode string.
|
||||
*/
|
||||
_convertToUnicode: function SS__convertToUnicode(aString, aCharset) {
|
||||
// Decoding primitives.
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
|
||||
try {
|
||||
converter.charset = aCharset || "UTF-8";
|
||||
return converter.ConvertToUnicode(aString);
|
||||
} catch(e) {
|
||||
return aString;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Performs a request to load the desired URL and returns a promise.
|
||||
*
|
||||
* @param aURL String
|
||||
* The URL we will request.
|
||||
* @returns Promise
|
||||
*
|
||||
* XXX: It may be better to use nsITraceableChannel to get to the sources
|
||||
* without relying on caching when we can (not for eval, etc.):
|
||||
* http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/
|
||||
*/
|
||||
_loadSource: function SA__loadSource() {
|
||||
let deferred = defer();
|
||||
let scheme;
|
||||
let url = this._url.split(" -> ").pop();
|
||||
|
||||
try {
|
||||
scheme = Services.io.extractScheme(url);
|
||||
} catch (e) {
|
||||
// In the xpcshell tests, the script url is the absolute path of the test
|
||||
// file, which will make a malformed URI error be thrown. Add the file
|
||||
// scheme prefix ourselves.
|
||||
url = "file://" + url;
|
||||
scheme = Services.io.extractScheme(url);
|
||||
}
|
||||
|
||||
switch (scheme) {
|
||||
case "file":
|
||||
case "chrome":
|
||||
case "resource":
|
||||
try {
|
||||
NetUtil.asyncFetch(url, function onFetch(aStream, aStatus) {
|
||||
if (!Components.isSuccessCode(aStatus)) {
|
||||
deferred.reject(new Error("Request failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
|
||||
deferred.resolve(this._convertToUnicode(source));
|
||||
aStream.close();
|
||||
}.bind(this));
|
||||
} catch (ex) {
|
||||
deferred.reject(new Error("Request failed"));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
let channel;
|
||||
try {
|
||||
channel = Services.io.newChannel(url, null, null);
|
||||
} catch (e if e.name == "NS_ERROR_UNKNOWN_PROTOCOL") {
|
||||
// On Windows xpcshell tests, c:/foo/bar can pass as a valid URL, but
|
||||
// newChannel won't be able to handle it.
|
||||
url = "file:///" + url;
|
||||
channel = Services.io.newChannel(url, null, null);
|
||||
}
|
||||
let chunks = [];
|
||||
let streamListener = {
|
||||
onStartRequest: function(aRequest, aContext, aStatusCode) {
|
||||
if (!Components.isSuccessCode(aStatusCode)) {
|
||||
deferred.reject("Request failed");
|
||||
}
|
||||
},
|
||||
onDataAvailable: function(aRequest, aContext, aStream, aOffset, aCount) {
|
||||
chunks.push(NetUtil.readInputStreamToString(aStream, aCount));
|
||||
},
|
||||
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||
if (!Components.isSuccessCode(aStatusCode)) {
|
||||
deferred.reject("Request failed");
|
||||
return;
|
||||
}
|
||||
|
||||
deferred.resolve(this._convertToUnicode(chunks.join(""),
|
||||
channel.contentCharset));
|
||||
}.bind(this)
|
||||
};
|
||||
|
||||
channel.loadFlags = channel.LOAD_FROM_CACHE;
|
||||
channel.asyncOpen(streamListener, null);
|
||||
break;
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
SourceActor.prototype.requestTypes = {
|
||||
|
@ -1963,14 +2038,7 @@ BreakpointActor.prototype = {
|
|||
hit: function BA_hit(aFrame) {
|
||||
// TODO: add the rest of the breakpoints on that line (bug 676602).
|
||||
let reason = { type: "breakpoint", actors: [ this.actorID ] };
|
||||
return this.threadActor._pauseAndRespond(aFrame, reason, function (aPacket) {
|
||||
let { url, line } = aPacket.frame.where;
|
||||
return this.threadActor.sources.getOriginalLocation(url, line)
|
||||
.then(function (aOrigPosition) {
|
||||
aPacket.frame.where = aOrigPosition;
|
||||
return aPacket;
|
||||
});
|
||||
}.bind(this));
|
||||
return this.threadActor._pauseAndRespond(aFrame, reason);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2292,183 +2360,6 @@ update(ChromeDebuggerActor.prototype, {
|
|||
});
|
||||
|
||||
|
||||
/**
|
||||
* Manages the sources for a thread. Handles source maps, locations in the
|
||||
* sources, etc for ThreadActors.
|
||||
*/
|
||||
function ThreadSources(aThreadActor, aUseSourceMaps,
|
||||
aAllowPredicate, aOnNewSource) {
|
||||
this._thread = aThreadActor;
|
||||
this._useSourceMaps = aUseSourceMaps;
|
||||
this._allow = aAllowPredicate;
|
||||
this._onNewSource = aOnNewSource;
|
||||
|
||||
// source map URL --> promise of SourceMapConsumer
|
||||
this._sourceMaps = Object.create(null);
|
||||
// generated source url --> promise of SourceMapConsumer
|
||||
this._sourceMapsByGeneratedSource = Object.create(null);
|
||||
// original source url --> promise of SourceMapConsumer
|
||||
this._sourceMapsByOriginalSource = Object.create(null);
|
||||
// source url --> SourceActor
|
||||
this._sourceActors = Object.create(null);
|
||||
// original url --> generated url
|
||||
this._generatedUrlsByOriginalUrl = Object.create(null);
|
||||
}
|
||||
|
||||
ThreadSources.prototype = {
|
||||
/**
|
||||
* Add a source to the current set of sources.
|
||||
*
|
||||
* Right now this takes a URL, but in the future it should
|
||||
* take a Debugger.Source. See bug 637572.
|
||||
*
|
||||
* @param string the source URL.
|
||||
* @returns a SourceActor representing the source or null.
|
||||
*/
|
||||
source: function TS_source(aURL) {
|
||||
if (!this._allow(aURL)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (aURL in this._sourceActors) {
|
||||
return this._sourceActors[aURL];
|
||||
}
|
||||
|
||||
let actor = new SourceActor(aURL, this._thread);
|
||||
this._thread.threadLifetimePool.addActor(actor);
|
||||
this._sourceActors[aURL] = actor;
|
||||
try {
|
||||
this._onNewSource(actor);
|
||||
} catch (e) {
|
||||
reportError(e);
|
||||
}
|
||||
return actor;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add all of the sources associated with the given script.
|
||||
*/
|
||||
sourcesForScript: function TS_sourcesForScript(aScript) {
|
||||
if (!this._useSourceMaps || !aScript.sourceMapURL) {
|
||||
return resolve([this.source(aScript.url)].filter(isNotNull));
|
||||
}
|
||||
|
||||
return this.sourceMap(aScript)
|
||||
.then(function (aSourceMap) {
|
||||
return [
|
||||
this.source(s) for (s of aSourceMap.sources)
|
||||
];
|
||||
}.bind(this), function (e) {
|
||||
reportError(e);
|
||||
delete this._sourceMaps[aScript.sourceMapURL];
|
||||
delete this._sourceMapsByGeneratedSource[aScript.url];
|
||||
return [this.source(aScript.url)];
|
||||
}.bind(this))
|
||||
.then(function (aSources) {
|
||||
return aSources.filter(isNotNull);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the source map for the given script.
|
||||
*/
|
||||
sourceMap: function TS_sourceMap(aScript) {
|
||||
if (aScript.url in this._sourceMapsByGeneratedSource) {
|
||||
return this._sourceMapsByGeneratedSource[aScript.url];
|
||||
}
|
||||
dbg_assert(aScript.sourceMapURL);
|
||||
let map = this._fetchSourceMap(aScript.sourceMapURL)
|
||||
.then(function (aSourceMap) {
|
||||
for (let s of aSourceMap.sources) {
|
||||
this._generatedUrlsByOriginalUrl[s] = aScript.url;
|
||||
this._sourceMapsByOriginalSource[s] = resolve(aSourceMap);
|
||||
}
|
||||
return aSourceMap;
|
||||
}.bind(this));
|
||||
this._sourceMapsByGeneratedSource[aScript.url] = map;
|
||||
return map;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch the source map located at the given url.
|
||||
*/
|
||||
_fetchSourceMap: function TS__featchSourceMap(aSourceMapURL) {
|
||||
if (aSourceMapURL in this._sourceMaps) {
|
||||
return this._sourceMaps[aSourceMapURL];
|
||||
} else {
|
||||
let promise = fetch(aSourceMapURL).then(function (rawSourceMap) {
|
||||
return new SourceMapConsumer(rawSourceMap);
|
||||
});
|
||||
this._sourceMaps[aSourceMapURL] = promise;
|
||||
return promise;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a promise for the location in the original source if the source is
|
||||
* source mapped, otherwise a promise of the same location.
|
||||
*
|
||||
* TODO bug 637572: take/return a column
|
||||
*/
|
||||
getOriginalLocation: function TS_getOriginalLocation(aSourceUrl, aLine) {
|
||||
if (aSourceUrl in this._sourceMapsByGeneratedSource) {
|
||||
return this._sourceMapsByGeneratedSource[aSourceUrl]
|
||||
.then(function (aSourceMap) {
|
||||
let { source, line } = aSourceMap.originalPositionFor({
|
||||
source: aSourceUrl,
|
||||
line: aLine,
|
||||
column: Infinity
|
||||
});
|
||||
return {
|
||||
url: source,
|
||||
line: line
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// No source map
|
||||
return resolve({
|
||||
url: aSourceUrl,
|
||||
line: aLine
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a promise of the location in the generated source corresponding to
|
||||
* the original source and line given.
|
||||
*
|
||||
* TODO bug 637572: take/return a column
|
||||
*/
|
||||
getGeneratedLocation: function TS_getGeneratedLocation(aSourceUrl, aLine) {
|
||||
if (aSourceUrl in this._sourceMapsByOriginalSource) {
|
||||
return this._sourceMapsByOriginalSource[aSourceUrl]
|
||||
.then(function (aSourceMap) {
|
||||
let { line } = aSourceMap.generatedPositionFor({
|
||||
source: aSourceUrl,
|
||||
line: aLine,
|
||||
column: Infinity
|
||||
});
|
||||
return {
|
||||
url: this._generatedUrlsByOriginalUrl[aSourceUrl],
|
||||
line: line
|
||||
};
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
// No source map
|
||||
return resolve({
|
||||
url: aSourceUrl,
|
||||
line: aLine
|
||||
});
|
||||
},
|
||||
|
||||
iter: function TS_iter() {
|
||||
for (let url in this._sourceActors) {
|
||||
yield this._sourceActors[url];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Utility functions.
|
||||
|
||||
/**
|
||||
|
@ -2489,126 +2380,3 @@ function update(aTarget, aNewAttrs) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if its argument is not null.
|
||||
*/
|
||||
function isNotNull(aThing) {
|
||||
return aThing !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a request to load the desired URL and returns a promise.
|
||||
*
|
||||
* @param aURL String
|
||||
* The URL we will request.
|
||||
* @returns Promise
|
||||
*
|
||||
* XXX: It may be better to use nsITraceableChannel to get to the sources
|
||||
* without relying on caching when we can (not for eval, etc.):
|
||||
* http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/
|
||||
*/
|
||||
function fetch(aURL) {
|
||||
let deferred = defer();
|
||||
let scheme;
|
||||
let url = aURL.split(" -> ").pop();
|
||||
let charset;
|
||||
|
||||
try {
|
||||
scheme = Services.io.extractScheme(url);
|
||||
} catch (e) {
|
||||
// In the xpcshell tests, the script url is the absolute path of the test
|
||||
// file, which will make a malformed URI error be thrown. Add the file
|
||||
// scheme prefix ourselves.
|
||||
url = "file://" + url;
|
||||
scheme = Services.io.extractScheme(url);
|
||||
}
|
||||
|
||||
switch (scheme) {
|
||||
case "file":
|
||||
case "chrome":
|
||||
case "resource":
|
||||
try {
|
||||
NetUtil.asyncFetch(url, function onFetch(aStream, aStatus) {
|
||||
if (!Components.isSuccessCode(aStatus)) {
|
||||
deferred.reject(new Error("Request failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
|
||||
deferred.resolve(source);
|
||||
aStream.close();
|
||||
});
|
||||
} catch (ex) {
|
||||
deferred.reject(new Error("Request failed: " + url));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
let channel;
|
||||
try {
|
||||
channel = Services.io.newChannel(url, null, null);
|
||||
} catch (e if e.name == "NS_ERROR_UNKNOWN_PROTOCOL") {
|
||||
// On Windows xpcshell tests, c:/foo/bar can pass as a valid URL, but
|
||||
// newChannel won't be able to handle it.
|
||||
url = "file:///" + url;
|
||||
channel = Services.io.newChannel(url, null, null);
|
||||
}
|
||||
let chunks = [];
|
||||
let streamListener = {
|
||||
onStartRequest: function(aRequest, aContext, aStatusCode) {
|
||||
if (!Components.isSuccessCode(aStatusCode)) {
|
||||
deferred.reject("Request failed");
|
||||
}
|
||||
},
|
||||
onDataAvailable: function(aRequest, aContext, aStream, aOffset, aCount) {
|
||||
chunks.push(NetUtil.readInputStreamToString(aStream, aCount));
|
||||
},
|
||||
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||
if (!Components.isSuccessCode(aStatusCode)) {
|
||||
deferred.reject("Request failed: " + url);
|
||||
return;
|
||||
}
|
||||
|
||||
charset = channel.contentCharset;
|
||||
deferred.resolve(chunks.join(""));
|
||||
}
|
||||
};
|
||||
|
||||
channel.loadFlags = channel.LOAD_FROM_CACHE;
|
||||
channel.asyncOpen(streamListener, null);
|
||||
break;
|
||||
}
|
||||
|
||||
return deferred.promise.then(function (source) {
|
||||
return convertToUnicode(source, charset);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a given string, encoded in a given character set, to unicode.
|
||||
*
|
||||
* @param string aString
|
||||
* A string.
|
||||
* @param string aCharset
|
||||
* A character set.
|
||||
*/
|
||||
function convertToUnicode(aString, aCharset=null) {
|
||||
// Decoding primitives.
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
try {
|
||||
converter.charset = aCharset || "UTF-8";
|
||||
return converter.ConvertToUnicode(aString);
|
||||
} catch(e) {
|
||||
return aString;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the given error in the error console and to stdout.
|
||||
*/
|
||||
function reportError(aError) {
|
||||
Cu.reportError(aError);
|
||||
dumpn(aError.message + ":\n" + aError.stack);
|
||||
}
|
||||
|
|
|
@ -26,14 +26,11 @@ addDebuggerToGlobal(this);
|
|||
|
||||
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
const { defer, resolve, reject } = Promise;
|
||||
Promise.all = Promise.promised(Array);
|
||||
|
||||
Cu.import("resource://gre/modules/devtools/SourceMap.jsm");
|
||||
|
||||
function dumpn(str) {
|
||||
// if (wantLogging) {
|
||||
if (wantLogging) {
|
||||
dump("DBG-SERVER: " + str + "\n");
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
function dbg_assert(cond, e) {
|
||||
|
@ -603,17 +600,6 @@ DebuggerServerConnection.prototype = {
|
|||
return null;
|
||||
},
|
||||
|
||||
_unknownError: function DSC__unknownError(aPrefix, aError) {
|
||||
let errorString = safeErrorString(aError);
|
||||
errorString += "\n" + aError.stack;
|
||||
Cu.reportError(errorString);
|
||||
dumpn(errorString);
|
||||
return {
|
||||
error: "unknownError",
|
||||
message: (aPrefix + "': " + errorString)
|
||||
};
|
||||
},
|
||||
|
||||
// Transport hooks.
|
||||
|
||||
/**
|
||||
|
@ -636,9 +622,12 @@ DebuggerServerConnection.prototype = {
|
|||
try {
|
||||
instance = new actor();
|
||||
} catch (e) {
|
||||
this.transport.send(this._unknownError(
|
||||
"Error occurred while creating actor '" + actor.name,
|
||||
e));
|
||||
Cu.reportError(e);
|
||||
this.transport.send({
|
||||
error: "unknownError",
|
||||
message: ("error occurred while creating actor '" + actor.name +
|
||||
"': " + safeErrorString(e))
|
||||
});
|
||||
}
|
||||
instance.parentID = actor.parentID;
|
||||
// We want the newly-constructed actor to completely replace the factory
|
||||
|
@ -650,14 +639,16 @@ DebuggerServerConnection.prototype = {
|
|||
}
|
||||
|
||||
var ret = null;
|
||||
|
||||
// Dispatch the request to the actor.
|
||||
if (actor.requestTypes && actor.requestTypes[aPacket.type]) {
|
||||
try {
|
||||
ret = actor.requestTypes[aPacket.type].bind(actor)(aPacket);
|
||||
} catch(e) {
|
||||
this.transport.send(this._unknownError(
|
||||
"error occurred while processing '" + aPacket.type,
|
||||
e));
|
||||
Cu.reportError(e);
|
||||
ret = { error: "unknownError",
|
||||
message: ("error occurred while processing '" + aPacket.type +
|
||||
"' request: " + safeErrorString(e)) };
|
||||
}
|
||||
} else {
|
||||
ret = { error: "unrecognizedPacketType",
|
||||
|
@ -672,19 +663,12 @@ DebuggerServerConnection.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
resolve(ret)
|
||||
.then(null, function (e) {
|
||||
return this._unknownError(
|
||||
"error occurred while processing '" + aPacket.type,
|
||||
e);
|
||||
}.bind(this))
|
||||
.then(function (aResponse) {
|
||||
if (!aResponse.from) {
|
||||
aResponse.from = aPacket.to;
|
||||
}
|
||||
return aResponse;
|
||||
})
|
||||
.then(this.transport.send.bind(this.transport));
|
||||
resolve(ret).then(function(returnPacket) {
|
||||
if (!returnPacket.from) {
|
||||
returnPacket.from = aPacket.to;
|
||||
}
|
||||
this.transport.send(returnPacket);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -107,7 +107,7 @@ function getTestGlobalContext(aClient, aName, aCallback) {
|
|||
|
||||
function attachTestGlobalClient(aClient, aName, aCallback) {
|
||||
getTestGlobalContext(aClient, aName, function(aContext) {
|
||||
aClient.attachThread(aContext.actor, aCallback, { useSourceMaps: true });
|
||||
aClient.attachThread(aContext.actor, aCallback);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ function attachTestTabAndResume(aClient, aName, aCallback) {
|
|||
aThreadClient.resume(function (aResponse) {
|
||||
aCallback(aResponse, aTabClient, aThreadClient);
|
||||
});
|
||||
}, { useSourceMaps: true });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -61,8 +61,8 @@ function test_child_breakpoint()
|
|||
|
||||
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
|
||||
"function foo() {\n" + // line0 + 1
|
||||
" this.a = 1;\n" + // line0 + 2
|
||||
" this.b = 2;\n" + // line0 + 3
|
||||
" this.a = 1;\n" + // line0 + 2
|
||||
" this.b = 2;\n" + // line0 + 3
|
||||
"}\n" + // line0 + 4
|
||||
"debugger;\n" + // line0 + 5
|
||||
"foo();\n"); // line0 + 6
|
||||
|
|
|
@ -38,7 +38,6 @@ function run_test()
|
|||
function test_attach(aContext)
|
||||
{
|
||||
gClient.request({ to: aContext.actor, type: "attach" }, function(aResponse) {
|
||||
do_check_true(!aResponse.error);
|
||||
do_check_eq(aResponse.type, "paused");
|
||||
|
||||
// Resume the thread and test the debugger statement.
|
||||
|
|
|
@ -16,6 +16,14 @@ function run_test()
|
|||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-stack");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.request = (function (request) {
|
||||
return function (aRequest, aOnResponse) {
|
||||
if (aRequest.type === "sources") {
|
||||
++gNumTimesSourcesSent;
|
||||
}
|
||||
return request.call(this, aRequest, aOnResponse);
|
||||
};
|
||||
}(gClient.request));
|
||||
gClient.connect(function () {
|
||||
attachTestGlobalClientAndResume(gClient, "test-stack", function (aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
|
|
|
@ -16,7 +16,6 @@ function run_test()
|
|||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-stack");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
|
||||
gClient.request = (function (request) {
|
||||
return function (aRequest, aOnResponse) {
|
||||
if (aRequest.type === "sources") {
|
||||
|
@ -34,7 +33,6 @@ function run_test()
|
|||
test_listing_zero_sources();
|
||||
});
|
||||
});
|
||||
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
|
@ -49,6 +47,6 @@ function test_listing_zero_sources()
|
|||
"Should only send one sources request at most, even though we"
|
||||
+ " might have had to send one to determine feature support.");
|
||||
|
||||
finishClient(gClient);
|
||||
finishClient(gClient);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check getSources functionality when there are lots of sources.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-sources");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function () {
|
||||
attachTestGlobalClientAndResume(gClient, "test-sources", function (aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_simple_listsources();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_simple_listsources()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||
gThreadClient.getSources(function (aResponse) {
|
||||
do_check_true(
|
||||
!aResponse.error,
|
||||
"There shouldn't be an error fetching large amounts of sources.");
|
||||
|
||||
do_check_true(aResponse.sources.some(function (s) {
|
||||
return s.url.match(/foo-999.js$/);
|
||||
}));
|
||||
|
||||
gThreadClient.resume(function () {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
Cu.evalInSandbox("function foo###() {return ###;}".replace(/###/g, i),
|
||||
gDebuggee,
|
||||
"1.8",
|
||||
"http://example.com/foo-" + i + ".js",
|
||||
1);
|
||||
}
|
||||
gDebuggee.eval("debugger;");
|
||||
}
|
|
@ -30,12 +30,10 @@ function test_pause_frame()
|
|||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
do_check_eq(aPacket.why.type, "exception");
|
||||
do_check_eq(aPacket.why.exception, 42);
|
||||
|
||||
gThreadClient.resume(function () {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
|
||||
gThreadClient.pauseOnExceptions(true);
|
||||
gThreadClient.resume();
|
||||
});
|
||||
|
|
|
@ -114,15 +114,21 @@ function test_profile(aClient, aProfiler)
|
|||
do_check_eq(typeof aResponse.profile.threads[0].samples, "object");
|
||||
do_check_neq(aResponse.profile.threads[0].samples.length, 0);
|
||||
|
||||
let location = stack.name + " (" + stack.filename + ":" + funcLine + ")";
|
||||
function some(array, cb) {
|
||||
for (var i = array.length; i; i--) {
|
||||
if (cb(array[i - 1]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// At least one sample is expected to have been in the busy wait above.
|
||||
do_check_true(aResponse.profile.threads[0].samples.some(function(sample) {
|
||||
do_check_true(some(aResponse.profile.threads[0].samples, function(sample) {
|
||||
return sample.name == "(root)" &&
|
||||
typeof sample.frames == "object" &&
|
||||
sample.frames.length != 0 &&
|
||||
sample.frames.some(function(f) {
|
||||
return (f.line == stack.lineNumber) &&
|
||||
(f.location == location);
|
||||
(f.location == stack.name + " (" + stack.filename + ":" + funcLine + ")");
|
||||
});
|
||||
}));
|
||||
|
||||
|
@ -153,13 +159,9 @@ function test_profiler_status()
|
|||
client.listTabs(function(aResponse) {
|
||||
var profiler = aResponse.profilerActor;
|
||||
do_check_false(Profiler.IsActive());
|
||||
client.request({
|
||||
to: profiler,
|
||||
type: "startProfiler",
|
||||
features: []
|
||||
}, function (aResponse) {
|
||||
client.request({ to: profiler, type: "startProfiler", features: [] }, function (aResponse) {
|
||||
do_check_true(Profiler.IsActive());
|
||||
client.close();
|
||||
client.close(function() { });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check basic source map integration with the "newSource" packet in the RDP.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
Components.utils.import('resource:///modules/devtools/SourceMap.jsm');
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-source-map");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestGlobalClientAndResume(gClient, "test-source-map", function(aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_simple_source_map();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_simple_source_map()
|
||||
{
|
||||
// Because we are source mapping, we should be notified of a.js, b.js, and
|
||||
// c.js as sources, and shouldn't receive abc.js or test_sourcemaps-01.js.
|
||||
let expectedSources = new Set(["http://example.com/www/js/a.js",
|
||||
"http://example.com/www/js/b.js",
|
||||
"http://example.com/www/js/c.js"]);
|
||||
|
||||
gClient.addListener("newSource", function _onNewSource(aEvent, aPacket) {
|
||||
do_check_eq(aEvent, "newSource");
|
||||
do_check_eq(aPacket.type, "newSource");
|
||||
do_check_true(!!aPacket.source);
|
||||
|
||||
do_check_true(expectedSources.has(aPacket.source.url),
|
||||
"The source url should be one of our original sources.");
|
||||
expectedSources.delete(aPacket.source.url);
|
||||
|
||||
if (expectedSources.size === 0) {
|
||||
gClient.removeListener("newSource", _onNewSource);
|
||||
finishClient(gClient);
|
||||
}
|
||||
});
|
||||
|
||||
let { code, map } = (new SourceNode(null, null, null, [
|
||||
new SourceNode(1, 0, "a.js", "function a() { return 'a'; }\n"),
|
||||
new SourceNode(1, 0, "b.js", "function b() { return 'b'; }\n"),
|
||||
new SourceNode(1, 0, "c.js", "function c() { return 'c'; }\n"),
|
||||
])).toStringWithSourceMap({
|
||||
file: "abc.js",
|
||||
sourceRoot: "http://example.com/www/js/"
|
||||
});
|
||||
|
||||
code += "//@ sourceMappingURL=data:text/json;base64," + btoa(map.toString());
|
||||
|
||||
Components.utils.evalInSandbox(code, gDebuggee, "1.8",
|
||||
"http://example.com/www/js/abc.js", 1);
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check basic source map integration with the "sources" packet in the RDP.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
Components.utils.import("resource:///modules/devtools/SourceMap.jsm");
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-source-map");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestGlobalClientAndResume(gClient, "test-source-map", function(aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_simple_source_map();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_simple_source_map()
|
||||
{
|
||||
// Because we are source mapping, we should be notified of a.js, b.js, and
|
||||
// c.js as sources, and shouldn"t receive abc.js or test_sourcemaps-01.js.
|
||||
let expectedSources = new Set(["http://example.com/www/js/a.js",
|
||||
"http://example.com/www/js/b.js",
|
||||
"http://example.com/www/js/c.js"]);
|
||||
|
||||
let numNewSources = 0;
|
||||
|
||||
gClient.addListener("newSource", function _onNewSource(aEvent, aPacket) {
|
||||
if (++numNewSources !== 3) {
|
||||
return;
|
||||
}
|
||||
gClient.removeListener("newSource", _onNewSource);
|
||||
|
||||
gThreadClient.getSources(function (aResponse) {
|
||||
do_check_true(!aResponse.error, "Should not get an error");
|
||||
|
||||
for (let s of aResponse.sources) {
|
||||
do_check_true(expectedSources.has(s.url),
|
||||
"The source's url should be one of our original sources");
|
||||
expectedSources.delete(s.url);
|
||||
}
|
||||
|
||||
do_check_eq(expectedSources.size, 0,
|
||||
"Shouldn't be expecting any more sources");
|
||||
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
|
||||
let { code, map } = (new SourceNode(null, null, null, [
|
||||
new SourceNode(1, 0, "a.js", "function a() { return 'a'; }\n"),
|
||||
new SourceNode(1, 0, "b.js", "function b() { return 'b'; }\n"),
|
||||
new SourceNode(1, 0, "c.js", "function c() { return 'c'; }\n"),
|
||||
])).toStringWithSourceMap({
|
||||
file: "abc.js",
|
||||
sourceRoot: "http://example.com/www/js/"
|
||||
});
|
||||
|
||||
code += "//@ sourceMappingURL=data:text/json;base64," + btoa(map.toString());
|
||||
|
||||
Components.utils.evalInSandbox(code, gDebuggee, "1.8",
|
||||
"http://example.com/www/js/abc.js", 1);
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check setting breakpoints in source mapped sources.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
Components.utils.import('resource:///modules/devtools/SourceMap.jsm');
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-source-map");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestGlobalClientAndResume(gClient, "test-source-map", function(aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_simple_source_map();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function testBreakpointMapping(aName, aCallback)
|
||||
{
|
||||
// Pause so we can set a breakpoint.
|
||||
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||
do_check_true(!aPacket.error);
|
||||
do_check_eq(aPacket.why.type, "debuggerStatement");
|
||||
|
||||
gThreadClient.setBreakpoint({
|
||||
url: "http://example.com/www/js/" + aName + ".js",
|
||||
// Setting the breakpoint on an empty line so that it is pushed down one
|
||||
// line and we can check the source mapped actualLocation later.
|
||||
line: 3,
|
||||
column: 0
|
||||
}, function (aResponse) {
|
||||
do_check_true(!aResponse.error);
|
||||
|
||||
// Actual location should come back source mapped still so that
|
||||
// breakpoints are displayed in the UI correctly, etc.
|
||||
do_check_eq(aResponse.actualLocation.line, 4);
|
||||
do_check_eq(aResponse.actualLocation.url,
|
||||
"http://example.com/www/js/" + aName + ".js");
|
||||
|
||||
// The eval will cause us to resume, then we get an unsolicited pause
|
||||
// because of our breakpoint, we resume again to finish the eval, and
|
||||
// finally receive our last pause which has the result of the client
|
||||
// evaluation.
|
||||
gThreadClient.eval(null, aName + "()", function (aResponse) {
|
||||
do_check_true(!aResponse.error, "Shouldn't be an error resuming to eval");
|
||||
do_check_eq(aResponse.type, "resumed");
|
||||
|
||||
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||
do_check_eq(aPacket.why.type, "breakpoint");
|
||||
// Assert that we paused because of the breakpoint at the correct
|
||||
// location in the code by testing that the value of `ret` is still
|
||||
// undefined.
|
||||
do_check_eq(aPacket.frame.environment.bindings.variables.ret.value.type,
|
||||
"undefined");
|
||||
|
||||
gThreadClient.resume(function (aResponse) {
|
||||
do_check_true(!aResponse.error);
|
||||
|
||||
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||
do_check_eq(aPacket.why.type, "clientEvaluated");
|
||||
do_check_eq(aPacket.why.frameFinished.return, aName);
|
||||
|
||||
gThreadClient.resume(function (aResponse) {
|
||||
do_check_true(!aResponse.error);
|
||||
aCallback();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("(" + function () {
|
||||
debugger;
|
||||
} + "());");
|
||||
}
|
||||
|
||||
function test_simple_source_map()
|
||||
{
|
||||
let expectedSources = new Set([
|
||||
"http://example.com/www/js/a.js",
|
||||
"http://example.com/www/js/b.js",
|
||||
"http://example.com/www/js/c.js"
|
||||
]);
|
||||
|
||||
gClient.addListener("newSource", function _onNewSource(aEvent, aPacket) {
|
||||
expectedSources.delete(aPacket.source.url);
|
||||
if (expectedSources.size > 0) {
|
||||
return;
|
||||
}
|
||||
gClient.removeListener("newSource", _onNewSource);
|
||||
|
||||
testBreakpointMapping("a", function () {
|
||||
testBreakpointMapping("b", function () {
|
||||
testBreakpointMapping("c", function () {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
let a = new SourceNode(null, null, null, [
|
||||
new SourceNode(1, 0, "a.js", "function a() {\n"),
|
||||
new SourceNode(2, 0, "a.js", " var ret;\n"),
|
||||
new SourceNode(3, 0, "a.js", " // Empty line\n"),
|
||||
new SourceNode(4, 0, "a.js", " ret = 'a';\n"),
|
||||
new SourceNode(5, 0, "a.js", " return ret;\n"),
|
||||
new SourceNode(6, 0, "a.js", "}\n")
|
||||
]);
|
||||
let b = new SourceNode(null, null, null, [
|
||||
new SourceNode(1, 0, "b.js", "function b() {\n"),
|
||||
new SourceNode(2, 0, "b.js", " var ret;\n"),
|
||||
new SourceNode(3, 0, "b.js", " // Empty line\n"),
|
||||
new SourceNode(4, 0, "b.js", " ret = 'b';\n"),
|
||||
new SourceNode(5, 0, "b.js", " return ret;\n"),
|
||||
new SourceNode(6, 0, "b.js", "}\n")
|
||||
]);
|
||||
let c = new SourceNode(null, null, null, [
|
||||
new SourceNode(1, 0, "c.js", "function c() {\n"),
|
||||
new SourceNode(2, 0, "c.js", " var ret;\n"),
|
||||
new SourceNode(3, 0, "c.js", " // Empty line\n"),
|
||||
new SourceNode(4, 0, "c.js", " ret = 'c';\n"),
|
||||
new SourceNode(5, 0, "c.js", " return ret;\n"),
|
||||
new SourceNode(6, 0, "c.js", "}\n")
|
||||
]);
|
||||
|
||||
let { code, map } = (new SourceNode(null, null, null, [
|
||||
a, b, c
|
||||
])).toStringWithSourceMap({
|
||||
file: "http://example.com/www/js/abc.js",
|
||||
sourceRoot: "http://example.com/www/js/"
|
||||
});
|
||||
|
||||
code += "//@ sourceMappingURL=data:text/json;base64," + btoa(map.toString());
|
||||
|
||||
Components.utils.evalInSandbox(code, gDebuggee, "1.8",
|
||||
"http://example.com/www/js/abc.js", 1);
|
||||
}
|
|
@ -18,7 +18,6 @@ function run_test()
|
|||
initSourcesBackwardsCompatDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-sources-compat");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
|
||||
gClient.request = (function (request) {
|
||||
return function (aRequest, aOnResponse) {
|
||||
if (aRequest.type === "sources") {
|
||||
|
@ -27,7 +26,6 @@ function run_test()
|
|||
return request.call(this, aRequest, aOnResponse);
|
||||
};
|
||||
}(gClient.request));
|
||||
|
||||
gClient.connect(function() {
|
||||
attachTestTabAndResume(gClient, "test-sources-compat", function (aResponse,
|
||||
aTabClient,
|
||||
|
|
|
@ -17,7 +17,6 @@ function run_test()
|
|||
initSourcesBackwardsCompatDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-sources-compat");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
|
||||
gClient.request = (function (request) {
|
||||
return function (aRequest, aOnResponse) {
|
||||
if (aRequest.type === "sources") {
|
||||
|
|
|
@ -30,26 +30,26 @@ function createRootActor()
|
|||
};
|
||||
|
||||
actor.thread.requestTypes["scripts"] = function (aRequest) {
|
||||
return this._discoverScriptsAndSources().then(function () {
|
||||
let scripts = [];
|
||||
for (let s of this.dbg.findScripts()) {
|
||||
if (!s.url) {
|
||||
continue;
|
||||
}
|
||||
let script = {
|
||||
url: s.url,
|
||||
startLine: s.startLine,
|
||||
lineCount: s.lineCount,
|
||||
source: this.sources.source(s.url).form()
|
||||
};
|
||||
scripts.push(script);
|
||||
}
|
||||
this._discoverScriptsAndSources();
|
||||
|
||||
return {
|
||||
from: this.actorID,
|
||||
scripts: scripts
|
||||
let scripts = [];
|
||||
for (let s of this.dbg.findScripts()) {
|
||||
if (!s.url) {
|
||||
continue;
|
||||
}
|
||||
let script = {
|
||||
url: s.url,
|
||||
startLine: s.startLine,
|
||||
lineCount: s.lineCount,
|
||||
source: this._getSource(s.url).form()
|
||||
};
|
||||
}.bind(this));
|
||||
scripts.push(script);
|
||||
}
|
||||
|
||||
return {
|
||||
from: this.actorID,
|
||||
scripts: scripts
|
||||
};
|
||||
};
|
||||
|
||||
// Pretend that we do not know about the "sources" packet to force the
|
||||
|
@ -70,7 +70,7 @@ function createRootActor()
|
|||
url: aScript.url,
|
||||
startLine: aScript.startLine,
|
||||
lineCount: aScript.lineCount,
|
||||
source: actor.thread.sources.source(aScript.url).form()
|
||||
source: actor.thread._getSource(aScript.url).form()
|
||||
});
|
||||
};
|
||||
}(actor.thread.onNewScript));
|
||||
|
|
|
@ -74,13 +74,9 @@ skip-if = toolkit == "gonk"
|
|||
reason = bug 820380
|
||||
[test_listsources-01.js]
|
||||
[test_listsources-02.js]
|
||||
[test_listsources-03.js]
|
||||
[test_new_source-01.js]
|
||||
[test_sources_backwards_compat-01.js]
|
||||
[test_sources_backwards_compat-02.js]
|
||||
[test_sourcemaps-01.js]
|
||||
[test_sourcemaps-02.js]
|
||||
[test_sourcemaps-03.js]
|
||||
[test_objectgrips-01.js]
|
||||
[test_objectgrips-02.js]
|
||||
[test_objectgrips-03.js]
|
||||
|
|
|
@ -44,7 +44,6 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||
* - sources: An array of URLs to the original source files.
|
||||
* - names: An array of identifiers which can be referrenced by individual mappings.
|
||||
* - sourceRoot: Optional. The URL root from which all sources are relative.
|
||||
* - sourcesContent: Optional. An array of contents of the original source files.
|
||||
* - mappings: A string of base64 VLQs which contain the actual mappings.
|
||||
* - file: The generated file this source map is associated with.
|
||||
*
|
||||
|
@ -71,7 +70,6 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||
var sources = util.getArg(sourceMap, 'sources');
|
||||
var names = util.getArg(sourceMap, 'names');
|
||||
var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null);
|
||||
var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null);
|
||||
var mappings = util.getArg(sourceMap, 'mappings');
|
||||
var file = util.getArg(sourceMap, 'file');
|
||||
|
||||
|
@ -81,8 +79,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||
|
||||
this._names = ArraySet.fromArray(names);
|
||||
this._sources = ArraySet.fromArray(sources);
|
||||
this.sourceRoot = sourceRoot;
|
||||
this.sourcesContent = sourcesContent;
|
||||
this._sourceRoot = sourceRoot;
|
||||
this.file = file;
|
||||
|
||||
// `this._generatedMappings` and `this._originalMappings` hold the parsed
|
||||
|
@ -124,7 +121,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||
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 ? util.join(this._sourceRoot, s) : s;
|
||||
}, this);
|
||||
}
|
||||
});
|
||||
|
@ -168,7 +165,12 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||
if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
|
||||
// Original source.
|
||||
temp = base64VLQ.decode(str);
|
||||
mapping.source = this._sources.at(previousSource + temp.value);
|
||||
if (aSourceRoot) {
|
||||
mapping.source = util.join(aSourceRoot, this._sources.at(previousSource + temp.value));
|
||||
}
|
||||
else {
|
||||
mapping.source = this._sources.at(previousSource + temp.value);
|
||||
}
|
||||
previousSource += temp.value;
|
||||
str = temp.rest;
|
||||
if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
|
||||
|
@ -202,9 +204,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||
}
|
||||
|
||||
this._generatedMappings.push(mapping);
|
||||
if (typeof mapping.originalLine === 'number') {
|
||||
this._originalMappings.push(mapping);
|
||||
}
|
||||
this._originalMappings.push(mapping);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,15 +291,11 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||
this._generatedMappings,
|
||||
"generatedLine",
|
||||
"generatedColumn",
|
||||
this._compareGeneratedPositions);
|
||||
this._compareGeneratedPositions)
|
||||
|
||||
if (mapping) {
|
||||
var source = util.getArg(mapping, 'source', null);
|
||||
if (source && this.sourceRoot) {
|
||||
source = util.join(this.sourceRoot, source);
|
||||
}
|
||||
return {
|
||||
source: source,
|
||||
source: util.getArg(mapping, 'source', null),
|
||||
line: util.getArg(mapping, 'originalLine', null),
|
||||
column: util.getArg(mapping, 'originalColumn', null),
|
||||
name: util.getArg(mapping, 'name', null)
|
||||
|
@ -314,32 +310,6 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the original source content. The only argument is
|
||||
* the url of the original source file. Returns null if no
|
||||
* original source content is availible.
|
||||
*/
|
||||
SourceMapConsumer.prototype.sourceContentFor =
|
||||
function SourceMapConsumer_sourceContentFor(aSource) {
|
||||
if (!this.sourcesContent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.sourceRoot) {
|
||||
// Try to remove the sourceRoot
|
||||
var relativeUrl = util.relative(this.sourceRoot, aSource);
|
||||
if (this._sources.has(relativeUrl)) {
|
||||
return this.sourcesContent[this._sources.indexOf(relativeUrl)];
|
||||
}
|
||||
}
|
||||
|
||||
if (this._sources.has(aSource)) {
|
||||
return this.sourcesContent[this._sources.indexOf(aSource)];
|
||||
}
|
||||
|
||||
throw new Error('"' + aSource + '" is not in the SourceMap.');
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the generated line and column information for the original source,
|
||||
* line, and column positions provided. The only argument is an object with
|
||||
|
@ -362,15 +332,11 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||
originalColumn: util.getArg(aArgs, 'column')
|
||||
};
|
||||
|
||||
if (this.sourceRoot) {
|
||||
needle.source = util.relative(this.sourceRoot, needle.source);
|
||||
}
|
||||
|
||||
var mapping = this._findMapping(needle,
|
||||
this._originalMappings,
|
||||
"originalLine",
|
||||
"originalColumn",
|
||||
this._compareOriginalPositions);
|
||||
this._compareOriginalPositions)
|
||||
|
||||
if (mapping) {
|
||||
return {
|
||||
|
@ -393,7 +359,8 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||
* generated line/column in this source map.
|
||||
*
|
||||
* @param Function aCallback
|
||||
* The function that is called with each mapping.
|
||||
* The function that is called with each mapping. This function should
|
||||
* not mutate the mapping.
|
||||
* @param Object aContext
|
||||
* Optional. If specified, this object will be the value of `this` every
|
||||
* time that `aCallback` is called.
|
||||
|
@ -421,21 +388,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||
throw new Error("Unknown order of iteration.");
|
||||
}
|
||||
|
||||
var sourceRoot = this.sourceRoot;
|
||||
mappings.map(function (mapping) {
|
||||
var source = mapping.source;
|
||||
if (source && sourceRoot) {
|
||||
source = util.join(sourceRoot, source);
|
||||
}
|
||||
return {
|
||||
source: source,
|
||||
generatedLine: mapping.generatedLine,
|
||||
generatedColumn: mapping.generatedColumn,
|
||||
originalLine: mapping.originalLine,
|
||||
originalColumn: mapping.originalColumn,
|
||||
name: mapping.name
|
||||
};
|
||||
}).forEach(aCallback, context);
|
||||
mappings.forEach(aCallback, context);
|
||||
};
|
||||
|
||||
exports.SourceMapConsumer = SourceMapConsumer;
|
||||
|
@ -473,37 +426,10 @@ define('source-map/util', ['require', 'exports', 'module' , ], function(require,
|
|||
function join(aRoot, aPath) {
|
||||
return aPath.charAt(0) === '/'
|
||||
? aPath
|
||||
: aRoot.replace(/\/$/, '') + '/' + aPath;
|
||||
: aRoot.replace(/\/*$/, '') + '/' + aPath;
|
||||
}
|
||||
exports.join = join;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
return '$' + aStr;
|
||||
}
|
||||
exports.toSetString = toSetString;
|
||||
|
||||
function fromSetString(aStr) {
|
||||
return aStr.substr(1);
|
||||
}
|
||||
exports.fromSetString = fromSetString;
|
||||
|
||||
function relative(aRoot, aPath) {
|
||||
aRoot = aRoot.replace(/\/$/, '');
|
||||
return aPath.indexOf(aRoot + '/') === 0
|
||||
? aPath.substr(aRoot.length + 1)
|
||||
: aPath;
|
||||
}
|
||||
exports.relative = relative;
|
||||
|
||||
});
|
||||
/* -*- Mode: js; js-indent-level: 2; -*- */
|
||||
/*
|
||||
|
@ -589,9 +515,7 @@ define('source-map/binary-search', ['require', 'exports', 'module' , ], function
|
|||
* Licensed under the New BSD license. See LICENSE or:
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
define('source-map/array-set', ['require', 'exports', 'module' , 'source-map/util'], function(require, exports, module) {
|
||||
|
||||
var util = require('source-map/util');
|
||||
define('source-map/array-set', ['require', 'exports', 'module' , ], function(require, exports, module) {
|
||||
|
||||
/**
|
||||
* A data structure which is a combination of an array and a set. Adding a new
|
||||
|
@ -615,6 +539,19 @@ define('source-map/array-set', ['require', 'exports', 'module' , 'source-map/ut
|
|||
return set;
|
||||
};
|
||||
|
||||
/**
|
||||
* Because behavior goes wacky when you set `__proto__` on `this._set`, 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
|
||||
*/
|
||||
ArraySet.prototype._toSetString = function ArraySet__toSetString (aStr) {
|
||||
return "$" + aStr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add the given string to this set.
|
||||
*
|
||||
|
@ -627,7 +564,7 @@ define('source-map/array-set', ['require', 'exports', 'module' , 'source-map/ut
|
|||
}
|
||||
var idx = this._array.length;
|
||||
this._array.push(aStr);
|
||||
this._set[util.toSetString(aStr)] = idx;
|
||||
this._set[this._toSetString(aStr)] = idx;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -637,7 +574,7 @@ define('source-map/array-set', ['require', 'exports', 'module' , 'source-map/ut
|
|||
*/
|
||||
ArraySet.prototype.has = function ArraySet_has(aStr) {
|
||||
return Object.prototype.hasOwnProperty.call(this._set,
|
||||
util.toSetString(aStr));
|
||||
this._toSetString(aStr));
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -647,7 +584,7 @@ define('source-map/array-set', ['require', 'exports', 'module' , 'source-map/ut
|
|||
*/
|
||||
ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) {
|
||||
if (this.has(aStr)) {
|
||||
return this._set[util.toSetString(aStr)];
|
||||
return this._set[this._toSetString(aStr)];
|
||||
}
|
||||
throw new Error('"' + aStr + '" is not in the set.');
|
||||
};
|
||||
|
@ -882,58 +819,10 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
|
|||
this._sources = new ArraySet();
|
||||
this._names = new ArraySet();
|
||||
this._mappings = [];
|
||||
this._sourcesContents = null;
|
||||
}
|
||||
|
||||
SourceMapGenerator.prototype._version = 3;
|
||||
|
||||
/**
|
||||
* Creates a new SourceMapGenerator based on a SourceMapConsumer
|
||||
*
|
||||
* @param aSourceMapConsumer The SourceMap.
|
||||
*/
|
||||
SourceMapGenerator.fromSourceMap =
|
||||
function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) {
|
||||
var sourceRoot = aSourceMapConsumer.sourceRoot;
|
||||
var generator = new SourceMapGenerator({
|
||||
file: aSourceMapConsumer.file,
|
||||
sourceRoot: sourceRoot
|
||||
});
|
||||
aSourceMapConsumer.eachMapping(function (mapping) {
|
||||
var newMapping = {
|
||||
generated: {
|
||||
line: mapping.generatedLine,
|
||||
column: mapping.generatedColumn
|
||||
}
|
||||
};
|
||||
|
||||
if (mapping.source) {
|
||||
newMapping.source = mapping.source;
|
||||
if (sourceRoot) {
|
||||
newMapping.source = util.relative(sourceRoot, newMapping.source);
|
||||
}
|
||||
|
||||
newMapping.original = {
|
||||
line: mapping.originalLine,
|
||||
column: mapping.originalColumn
|
||||
};
|
||||
|
||||
if (mapping.name) {
|
||||
newMapping.name = mapping.name;
|
||||
}
|
||||
}
|
||||
|
||||
generator.addMapping(newMapping);
|
||||
});
|
||||
aSourceMapConsumer.sources.forEach(function (sourceFile) {
|
||||
var content = aSourceMapConsumer.sourceContentFor(sourceFile);
|
||||
if (content) {
|
||||
generator.setSourceContent(sourceFile, content);
|
||||
}
|
||||
});
|
||||
return generator;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a single mapping from original source line and column to the generated
|
||||
* source's line and column for this source map being created. The mapping
|
||||
|
@ -969,110 +858,6 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the source content for a source file.
|
||||
*/
|
||||
SourceMapGenerator.prototype.setSourceContent =
|
||||
function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) {
|
||||
var source = aSourceFile;
|
||||
if (this._sourceRoot) {
|
||||
source = util.relative(this._sourceRoot, source);
|
||||
}
|
||||
|
||||
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 {
|
||||
// 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)];
|
||||
if (Object.keys(this._sourcesContents).length === 0) {
|
||||
this._sourcesContents = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Applies the mappings of a sub-source-map for a specific source file to the
|
||||
* source map being generated. Each mapping to the supplied source file is
|
||||
* rewritten using the supplied source map. Note: The resolution for the
|
||||
* resulting mappings is the minimium of this map and the supplied map.
|
||||
*
|
||||
* @param aSourceMapConsumer The source map to be applied.
|
||||
* @param aSourceFile Optional. The filename of the source file.
|
||||
* If omitted, SourceMapConsumer's file property will be used.
|
||||
*/
|
||||
SourceMapGenerator.prototype.applySourceMap =
|
||||
function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) {
|
||||
// If aSourceFile is omitted, we will use the file property of the SourceMap
|
||||
if (!aSourceFile) {
|
||||
aSourceFile = aSourceMapConsumer.file;
|
||||
}
|
||||
var sourceRoot = this._sourceRoot;
|
||||
// Make "aSourceFile" relative if an absolute Url is passed.
|
||||
if (sourceRoot) {
|
||||
aSourceFile = util.relative(sourceRoot, aSourceFile);
|
||||
}
|
||||
// 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"
|
||||
this._mappings.forEach(function (mapping) {
|
||||
if (mapping.source === aSourceFile && mapping.original) {
|
||||
// Check if it can be mapped by the source map, then update the mapping.
|
||||
var original = aSourceMapConsumer.originalPositionFor({
|
||||
line: mapping.original.line,
|
||||
column: mapping.original.column
|
||||
});
|
||||
if (original.source !== null) {
|
||||
// Copy mapping
|
||||
if (sourceRoot) {
|
||||
mapping.source = util.relative(sourceRoot, original.source);
|
||||
} else {
|
||||
mapping.source = original.source;
|
||||
}
|
||||
mapping.original.line = original.line;
|
||||
mapping.original.column = original.column;
|
||||
if (original.name !== null && mapping.name !== null) {
|
||||
// Only use the identifier name if it's an identifier
|
||||
// in both SourceMaps
|
||||
mapping.name = original.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var source = mapping.source;
|
||||
if (source && !newSources.has(source)) {
|
||||
newSources.add(source);
|
||||
}
|
||||
|
||||
var name = mapping.name;
|
||||
if (name && !newNames.has(name)) {
|
||||
newNames.add(name);
|
||||
}
|
||||
|
||||
}, this);
|
||||
this._sources = newSources;
|
||||
this._names = newNames;
|
||||
|
||||
// Copy sourcesContents of applied map.
|
||||
aSourceMapConsumer.sources.forEach(function (sourceFile) {
|
||||
var content = aSourceMapConsumer.sourceContentFor(sourceFile);
|
||||
if (content) {
|
||||
if (sourceRoot) {
|
||||
sourceFile = util.relative(sourceRoot, sourceFile);
|
||||
}
|
||||
this.setSourceContent(sourceFile, content);
|
||||
}
|
||||
}, this);
|
||||
};
|
||||
|
||||
/**
|
||||
* A mapping can have one of the three levels of data:
|
||||
*
|
||||
|
@ -1193,17 +978,6 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
|
|||
if (this._sourceRoot) {
|
||||
map.sourceRoot = this._sourceRoot;
|
||||
}
|
||||
if (this._sourcesContents) {
|
||||
map.sourcesContent = map.sources.map(function (source) {
|
||||
if (map.sourceRoot) {
|
||||
source = util.relative(map.sourceRoot, source);
|
||||
}
|
||||
return Object.prototype.hasOwnProperty.call(
|
||||
this._sourcesContents, util.toSetString(source))
|
||||
? this._sourcesContents[util.toSetString(source)]
|
||||
: null;
|
||||
}, this);
|
||||
}
|
||||
return map;
|
||||
};
|
||||
|
||||
|
@ -1224,10 +998,9 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
|
|||
* Licensed under the New BSD license. See LICENSE or:
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/source-map-generator', 'source-map/util'], function(require, exports, module) {
|
||||
define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/source-map-generator'], function(require, exports, module) {
|
||||
|
||||
var SourceMapGenerator = require('source-map/source-map-generator').SourceMapGenerator;
|
||||
var util = require('source-map/util');
|
||||
|
||||
/**
|
||||
* SourceNodes provide a way to abstract over interpolating/concatenating
|
||||
|
@ -1239,121 +1012,15 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
|
|||
* @param aSource The original source's filename.
|
||||
* @param aChunks Optional. An array of strings which are snippets of
|
||||
* generated JS, or other SourceNodes.
|
||||
* @param aName The original identifier.
|
||||
*/
|
||||
function SourceNode(aLine, aColumn, aSource, aChunks, aName) {
|
||||
function SourceNode(aLine, aColumn, aSource, aChunks) {
|
||||
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;
|
||||
this.column = aColumn;
|
||||
this.source = aSource;
|
||||
if (aChunks != null) this.add(aChunks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SourceNode from generated code and a SourceMapConsumer.
|
||||
*
|
||||
* @param aGeneratedCode The generated code
|
||||
* @param aSourceMapConsumer The SourceMap for the generated code
|
||||
*/
|
||||
SourceNode.fromStringWithSourceMap =
|
||||
function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) {
|
||||
// The SourceNode we want to fill with the generated code
|
||||
// and the SourceMap
|
||||
var node = new SourceNode();
|
||||
|
||||
// The generated code
|
||||
// Processed fragments are removed from this array.
|
||||
var remainingLines = aGeneratedCode.split('\n');
|
||||
|
||||
// We need to remember the position of "remainingLines"
|
||||
var lastGeneratedLine = 1, lastGeneratedColumn = 0;
|
||||
|
||||
// The generate SourceNodes we need a code range.
|
||||
// To extract it current and last mapping is used.
|
||||
// Here we store the last mapping.
|
||||
var lastMapping = null;
|
||||
|
||||
aSourceMapConsumer.eachMapping(function (mapping) {
|
||||
if (lastMapping === null) {
|
||||
// We add the generated code until the first mapping
|
||||
// to the SourceNode without any mapping.
|
||||
// Each line is added as separate string.
|
||||
while (lastGeneratedLine < mapping.generatedLine) {
|
||||
node.add(remainingLines.shift() + "\n");
|
||||
lastGeneratedLine++;
|
||||
}
|
||||
if (lastGeneratedColumn < mapping.generatedColumn) {
|
||||
var nextLine = remainingLines[0];
|
||||
node.add(nextLine.substr(0, mapping.generatedColumn));
|
||||
remainingLines[0] = nextLine.substr(mapping.generatedColumn);
|
||||
lastGeneratedColumn = mapping.generatedColumn;
|
||||
}
|
||||
} else {
|
||||
// We add the code from "lastMapping" to "mapping":
|
||||
// First check if there is a new line in between.
|
||||
if (lastGeneratedLine < mapping.generatedLine) {
|
||||
var code = "";
|
||||
// Associate full lines with "lastMapping"
|
||||
do {
|
||||
code += remainingLines.shift() + "\n";
|
||||
lastGeneratedLine++;
|
||||
lastGeneratedColumn = 0;
|
||||
} while (lastGeneratedLine < mapping.generatedLine);
|
||||
// When we reached the correct line, we add code until we
|
||||
// reach the correct column too.
|
||||
if (lastGeneratedColumn < mapping.generatedColumn) {
|
||||
var nextLine = remainingLines[0];
|
||||
code += nextLine.substr(0, mapping.generatedColumn);
|
||||
remainingLines[0] = nextLine.substr(mapping.generatedColumn);
|
||||
lastGeneratedColumn = mapping.generatedColumn;
|
||||
}
|
||||
// Create the SourceNode.
|
||||
addMappingWithCode(lastMapping, code);
|
||||
} else {
|
||||
// There is no new line in between.
|
||||
// Associate the code between "lastGeneratedColumn" and
|
||||
// "mapping.generatedColumn" with "lastMapping"
|
||||
var nextLine = remainingLines[0];
|
||||
var code = nextLine.substr(0, mapping.generatedColumn -
|
||||
lastGeneratedColumn);
|
||||
remainingLines[0] = nextLine.substr(mapping.generatedColumn -
|
||||
lastGeneratedColumn);
|
||||
lastGeneratedColumn = mapping.generatedColumn;
|
||||
addMappingWithCode(lastMapping, code);
|
||||
}
|
||||
}
|
||||
lastMapping = mapping;
|
||||
}, this);
|
||||
// We have processed all mappings.
|
||||
// Associate the remaining code in the current line with "lastMapping"
|
||||
// and add the remaining lines without any mapping
|
||||
addMappingWithCode(lastMapping, remainingLines.join("\n"));
|
||||
|
||||
// Copy sourcesContent into SourceNode
|
||||
aSourceMapConsumer.sources.forEach(function (sourceFile) {
|
||||
var content = aSourceMapConsumer.sourceContentFor(sourceFile);
|
||||
if (content) {
|
||||
node.setSourceContent(sourceFile, content);
|
||||
}
|
||||
});
|
||||
|
||||
return node;
|
||||
|
||||
function addMappingWithCode(mapping, code) {
|
||||
if (mapping.source === undefined) {
|
||||
node.add(code);
|
||||
} else {
|
||||
node.add(new SourceNode(mapping.originalLine,
|
||||
mapping.originalColumn,
|
||||
mapping.source,
|
||||
code,
|
||||
mapping.name));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a chunk of generated JS to this source node.
|
||||
*
|
||||
|
@ -1416,10 +1083,7 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
|
|||
}
|
||||
else {
|
||||
if (chunk !== '') {
|
||||
aFn(chunk, { source: this.source,
|
||||
line: this.line,
|
||||
column: this.column,
|
||||
name: this.name });
|
||||
aFn(chunk, { source: this.source, line: this.line, column: this.column });
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
|
@ -1434,7 +1098,7 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
|
|||
SourceNode.prototype.join = function SourceNode_join(aSep) {
|
||||
var newChildren;
|
||||
var i;
|
||||
var len = this.children.length;
|
||||
var len = this.children.length
|
||||
if (len > 0) {
|
||||
newChildren = [];
|
||||
for (i = 0; i < len-1; i++) {
|
||||
|
@ -1468,36 +1132,6 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
|
|||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the source content for a source file. This will be added to the SourceMapGenerator
|
||||
* in the sourcesContent field.
|
||||
*
|
||||
* @param aSourceFile The filename of the source file
|
||||
* @param aSourceContent The content of the source file
|
||||
*/
|
||||
SourceNode.prototype.setSourceContent =
|
||||
function SourceNode_setSourceContent(aSourceFile, aSourceContent) {
|
||||
this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Walk over the tree of SourceNodes. The walking function is called for each
|
||||
* source file content and is passed the filename and source content.
|
||||
*
|
||||
* @param aFn The traversal function.
|
||||
*/
|
||||
SourceNode.prototype.walkSourceContents =
|
||||
function SourceNode_walkSourceContents(aFn) {
|
||||
this.children.forEach(function (chunk) {
|
||||
if (chunk instanceof SourceNode) {
|
||||
chunk.walkSourceContents(aFn);
|
||||
}
|
||||
}, this);
|
||||
Object.keys(this.sourceContents).forEach(function (sourceFileKey) {
|
||||
aFn(util.fromSetString(sourceFileKey), this.sourceContents[sourceFileKey]);
|
||||
}, this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the string representation of this source node. Walks over the tree
|
||||
* and concatenates all the various snippets together to one string.
|
||||
|
@ -1521,36 +1155,25 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
|
|||
column: 0
|
||||
};
|
||||
var map = new SourceMapGenerator(aArgs);
|
||||
var sourceMappingActive = false;
|
||||
this.walk(function (chunk, original) {
|
||||
generated.code += chunk;
|
||||
if (original.source !== null
|
||||
&& original.line !== null
|
||||
&& original.column !== null) {
|
||||
if (original.source != null
|
||||
&& original.line != null
|
||||
&& original.column != null) {
|
||||
map.addMapping({
|
||||
source: original.source,
|
||||
original: {
|
||||
line: original.line,
|
||||
column: original.column
|
||||
},
|
||||
generated: {
|
||||
line: generated.line,
|
||||
column: generated.column
|
||||
},
|
||||
name: original.name
|
||||
});
|
||||
sourceMappingActive = true;
|
||||
} else if (sourceMappingActive) {
|
||||
map.addMapping({
|
||||
generated: {
|
||||
line: generated.line,
|
||||
column: generated.column
|
||||
}
|
||||
});
|
||||
sourceMappingActive = false;
|
||||
}
|
||||
chunk.split('').forEach(function (ch) {
|
||||
if (ch === '\n') {
|
||||
chunk.split('').forEach(function (char) {
|
||||
if (char === '\n') {
|
||||
generated.line++;
|
||||
generated.column = 0;
|
||||
} else {
|
||||
|
@ -1558,9 +1181,6 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
|
|||
}
|
||||
});
|
||||
});
|
||||
this.walkSourceContents(function (sourceFile, sourceContent) {
|
||||
map.setSourceContent(sourceFile, sourceContent);
|
||||
});
|
||||
|
||||
return { code: generated.code, map: map };
|
||||
};
|
||||
|
@ -1571,6 +1191,6 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
|
|||
/* -*- Mode: js; js-indent-level: 2; -*- */
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
this.SourceMapConsumer = require('source-map/source-map-consumer').SourceMapConsumer;
|
||||
this.SourceMapGenerator = require('source-map/source-map-generator').SourceMapGenerator;
|
||||
this.SourceNode = require('source-map/source-node').SourceNode;
|
||||
let SourceMapConsumer = require('source-map/source-map-consumer').SourceMapConsumer;
|
||||
let SourceMapGenerator = require('source-map/source-map-generator').SourceMapGenerator;
|
||||
let SourceNode = require('source-map/source-node').SourceNode;
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
Components.utils.import('resource://gre/modules/devtools/Require.jsm');
|
||||
Components.utils.import('resource://gre/modules/devtools/SourceMap.jsm');
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "define", "runSourceMapTests" ];
|
||||
let EXPORTED_SYMBOLS = [ "define", "runSourceMapTests" ];
|
||||
/* -*- Mode: js; js-indent-level: 2; -*- */
|
||||
/*
|
||||
* Copyright 2011 Mozilla Foundation and contributors
|
||||
|
@ -78,9 +78,7 @@ define('test/source-map/assert', ['exports'], function (exports) {
|
|||
* Licensed under the New BSD license. See LICENSE or:
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
define('test/source-map/util', ['require', 'exports', 'module' , 'lib/source-map/util'], function(require, exports, module) {
|
||||
|
||||
var util = require('source-map/util');
|
||||
define('test/source-map/util', ['require', 'exports', 'module' , ], function(require, exports, module) {
|
||||
|
||||
// This is a test mapping which maps functions from two different files
|
||||
// (one.js and two.js) to a minified generated source.
|
||||
|
@ -101,8 +99,6 @@ define('test/source-map/util', ['require', 'exports', 'module' , 'lib/source-ma
|
|||
//
|
||||
// ONE.foo=function(a){return baz(a);};
|
||||
// TWO.inc=function(a){return a+1;};
|
||||
exports.testGeneratedCode = " ONE.foo=function(a){return baz(a);};\n"+
|
||||
" TWO.inc=function(a){return a+1;};";
|
||||
exports.testMap = {
|
||||
version: 3,
|
||||
file: 'min.js',
|
||||
|
@ -111,22 +107,6 @@ define('test/source-map/util', ['require', 'exports', 'module' , 'lib/source-ma
|
|||
sourceRoot: '/the/root',
|
||||
mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'
|
||||
};
|
||||
exports.testMapWithSourcesContent = {
|
||||
version: 3,
|
||||
file: 'min.js',
|
||||
names: ['bar', 'baz', 'n'],
|
||||
sources: ['one.js', 'two.js'],
|
||||
sourcesContent: [
|
||||
' ONE.foo = function (bar) {\n' +
|
||||
' return baz(bar);\n' +
|
||||
' };',
|
||||
' TWO.inc = function (n) {\n' +
|
||||
' return n + 1;\n' +
|
||||
' };'
|
||||
],
|
||||
sourceRoot: '/the/root',
|
||||
mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'
|
||||
};
|
||||
|
||||
function assertMapping(generatedLine, generatedColumn, originalSource,
|
||||
originalLine, originalColumn, name, map, assert,
|
||||
|
@ -145,8 +125,7 @@ define('test/source-map/util', ['require', 'exports', 'module' , 'lib/source-ma
|
|||
assert.equal(origMapping.column, originalColumn,
|
||||
'Incorrect column, expected ' + JSON.stringify(originalColumn)
|
||||
+ ', got ' + JSON.stringify(origMapping.column));
|
||||
assert.equal(origMapping.source,
|
||||
originalSource ? util.join(map._sourceRoot, originalSource) : null,
|
||||
assert.equal(origMapping.source, originalSource,
|
||||
'Incorrect source, expected ' + JSON.stringify(originalSource)
|
||||
+ ', got ' + JSON.stringify(origMapping.source));
|
||||
}
|
||||
|
@ -167,111 +146,6 @@ define('test/source-map/util', ['require', 'exports', 'module' , 'lib/source-ma
|
|||
}
|
||||
exports.assertMapping = assertMapping;
|
||||
|
||||
function assertEqualMaps(assert, actualMap, expectedMap) {
|
||||
assert.equal(actualMap.version, expectedMap.version, "version mismatch");
|
||||
assert.equal(actualMap.file, expectedMap.file, "file mismatch");
|
||||
assert.equal(actualMap.names.length,
|
||||
expectedMap.names.length,
|
||||
"names length mismatch: " +
|
||||
actualMap.names.join(", ") + " != " + expectedMap.names.join(", "));
|
||||
for (var i = 0; i < actualMap.names.length; i++) {
|
||||
assert.equal(actualMap.names[i],
|
||||
expectedMap.names[i],
|
||||
"names[" + i + "] mismatch: " +
|
||||
actualMap.names.join(", ") + " != " + expectedMap.names.join(", "));
|
||||
}
|
||||
assert.equal(actualMap.sources.length,
|
||||
expectedMap.sources.length,
|
||||
"sources length mismatch: " +
|
||||
actualMap.sources.join(", ") + " != " + expectedMap.sources.join(", "));
|
||||
for (var i = 0; i < actualMap.sources.length; i++) {
|
||||
assert.equal(actualMap.sources[i],
|
||||
expectedMap.sources[i],
|
||||
"sources[" + i + "] length mismatch: " +
|
||||
actualMap.sources.join(", ") + " != " + expectedMap.sources.join(", "));
|
||||
}
|
||||
assert.equal(actualMap.sourceRoot,
|
||||
expectedMap.sourceRoot,
|
||||
"sourceRoot mismatch: " +
|
||||
actualMap.sourceRoot + " != " + expectedMap.sourceRoot);
|
||||
assert.equal(actualMap.mappings, expectedMap.mappings, "mappings mismatch");
|
||||
if (actualMap.sourcesContent) {
|
||||
assert.equal(actualMap.sourcesContent.length,
|
||||
expectedMap.sourcesContent.length,
|
||||
"sourcesContent length mismatch");
|
||||
for (var i = 0; i < actualMap.sourcesContent.length; i++) {
|
||||
assert.equal(actualMap.sourcesContent[i],
|
||||
expectedMap.sourcesContent[i],
|
||||
"sourcesContent[" + i + "] mismatch");
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.assertEqualMaps = assertEqualMaps;
|
||||
|
||||
});
|
||||
/* -*- 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
|
||||
*/
|
||||
define('lib/source-map/util', ['require', 'exports', 'module' , ], function(require, exports, module) {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
function join(aRoot, aPath) {
|
||||
return aPath.charAt(0) === '/'
|
||||
? aPath
|
||||
: aRoot.replace(/\/$/, '') + '/' + aPath;
|
||||
}
|
||||
exports.join = join;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
return '$' + aStr;
|
||||
}
|
||||
exports.toSetString = toSetString;
|
||||
|
||||
function fromSetString(aStr) {
|
||||
return aStr.substr(1);
|
||||
}
|
||||
exports.fromSetString = fromSetString;
|
||||
|
||||
function relative(aRoot, aPath) {
|
||||
aRoot = aRoot.replace(/\/$/, '');
|
||||
return aPath.indexOf(aRoot + '/') === 0
|
||||
? aPath.substr(aRoot.length + 1)
|
||||
: aPath;
|
||||
}
|
||||
exports.relative = relative;
|
||||
|
||||
});
|
||||
/* -*- Mode: js; js-indent-level: 2; -*- */
|
||||
/*
|
||||
|
@ -293,4 +167,3 @@ function runSourceMapTests(modName, do_throw) {
|
|||
}
|
||||
|
||||
}
|
||||
this.runSourceMapTests = runSourceMapTests;
|
||||
|
|
|
@ -15,7 +15,6 @@ Components.utils.import('resource://test/Utils.jsm');
|
|||
define("test/source-map/test-source-map-consumer", ["require", "exports", "module"], function (require, exports, module) {
|
||||
|
||||
var SourceMapConsumer = require('source-map/source-map-consumer').SourceMapConsumer;
|
||||
var SourceMapGenerator = require('source-map/source-map-generator').SourceMapGenerator;
|
||||
|
||||
exports['test that we can instantiate with a string or an objects'] = function (assert, util) {
|
||||
assert.doesNotThrow(function () {
|
||||
|
@ -98,10 +97,6 @@ define("test/source-map/test-source-map-consumer", ["require", "exports", "modul
|
|||
map.eachMapping(function (mapping) {
|
||||
assert.ok(mapping.generatedLine >= previousLine);
|
||||
|
||||
if (mapping.source) {
|
||||
assert.equal(mapping.source.indexOf(util.testMap.sourceRoot), 0);
|
||||
}
|
||||
|
||||
if (mapping.generatedLine === previousLine) {
|
||||
assert.ok(mapping.generatedColumn >= previousColumn);
|
||||
previousColumn = mapping.generatedColumn;
|
||||
|
@ -149,112 +144,6 @@ define("test/source-map/test-source-map-consumer", ["require", "exports", "modul
|
|||
}, context);
|
||||
};
|
||||
|
||||
exports['test that the `sourcesContent` field has the original sources'] = function (assert, util) {
|
||||
var map = new SourceMapConsumer(util.testMapWithSourcesContent);
|
||||
var sourcesContent = map.sourcesContent;
|
||||
|
||||
assert.equal(sourcesContent[0], ' ONE.foo = function (bar) {\n return baz(bar);\n };');
|
||||
assert.equal(sourcesContent[1], ' TWO.inc = function (n) {\n return n + 1;\n };');
|
||||
assert.equal(sourcesContent.length, 2);
|
||||
};
|
||||
|
||||
exports['test that we can get the original sources for the sources'] = function (assert, util) {
|
||||
var map = new SourceMapConsumer(util.testMapWithSourcesContent);
|
||||
var sources = map.sources;
|
||||
|
||||
assert.equal(map.sourceContentFor(sources[0]), ' ONE.foo = function (bar) {\n return baz(bar);\n };');
|
||||
assert.equal(map.sourceContentFor(sources[1]), ' TWO.inc = function (n) {\n return n + 1;\n };');
|
||||
assert.equal(map.sourceContentFor("one.js"), ' ONE.foo = function (bar) {\n return baz(bar);\n };');
|
||||
assert.equal(map.sourceContentFor("two.js"), ' TWO.inc = function (n) {\n return n + 1;\n };');
|
||||
assert.throws(function () {
|
||||
map.sourceContentFor("");
|
||||
}, Error);
|
||||
assert.throws(function () {
|
||||
map.sourceContentFor("/the/root/three.js");
|
||||
}, Error);
|
||||
assert.throws(function () {
|
||||
map.sourceContentFor("three.js");
|
||||
}, Error);
|
||||
};
|
||||
|
||||
exports['test sourceRoot + generatedPositionFor'] = function (assert, util) {
|
||||
var map = new SourceMapGenerator({
|
||||
sourceRoot: 'foo/bar',
|
||||
file: 'baz.js'
|
||||
});
|
||||
map.addMapping({
|
||||
original: { line: 1, column: 1 },
|
||||
generated: { line: 2, column: 2 },
|
||||
source: 'bang.coffee'
|
||||
});
|
||||
map.addMapping({
|
||||
original: { line: 5, column: 5 },
|
||||
generated: { line: 6, column: 6 },
|
||||
source: 'bang.coffee'
|
||||
});
|
||||
map = new SourceMapConsumer(map.toString());
|
||||
|
||||
// Should handle without sourceRoot.
|
||||
var pos = map.generatedPositionFor({
|
||||
line: 1,
|
||||
column: 1,
|
||||
source: 'bang.coffee'
|
||||
});
|
||||
|
||||
assert.equal(pos.line, 2);
|
||||
assert.equal(pos.column, 2);
|
||||
|
||||
// Should handle with sourceRoot.
|
||||
var pos = map.generatedPositionFor({
|
||||
line: 1,
|
||||
column: 1,
|
||||
source: 'foo/bar/bang.coffee'
|
||||
});
|
||||
|
||||
assert.equal(pos.line, 2);
|
||||
assert.equal(pos.column, 2);
|
||||
};
|
||||
|
||||
exports['test sourceRoot + originalPositionFor'] = function (assert, util) {
|
||||
var map = new SourceMapGenerator({
|
||||
sourceRoot: 'foo/bar',
|
||||
file: 'baz.js'
|
||||
});
|
||||
map.addMapping({
|
||||
original: { line: 1, column: 1 },
|
||||
generated: { line: 2, column: 2 },
|
||||
source: 'bang.coffee'
|
||||
});
|
||||
map = new SourceMapConsumer(map.toString());
|
||||
|
||||
var pos = map.originalPositionFor({
|
||||
line: 2,
|
||||
column: 2,
|
||||
});
|
||||
|
||||
// Should always have the prepended source root
|
||||
assert.equal(pos.source, 'foo/bar/bang.coffee');
|
||||
assert.equal(pos.line, 1);
|
||||
assert.equal(pos.column, 1);
|
||||
};
|
||||
|
||||
exports['test github issue #56'] = function (assert, util) {
|
||||
var map = new SourceMapGenerator({
|
||||
sourceRoot: 'http://',
|
||||
file: 'www.example.com/foo.js'
|
||||
});
|
||||
map.addMapping({
|
||||
original: { line: 1, column: 1 },
|
||||
generated: { line: 2, column: 2 },
|
||||
source: 'www.example.com/original.js'
|
||||
});
|
||||
map = new SourceMapConsumer(map.toString());
|
||||
|
||||
var sources = map.sources;
|
||||
assert.equal(map.sources.length, 1);
|
||||
assert.equal(map.sources[0], 'http://www.example.com/original.js');
|
||||
};
|
||||
|
||||
});
|
||||
function run_test() {
|
||||
runSourceMapTests('test/source-map/test-source-map-consumer', do_throw);
|
||||
|
|
|
@ -15,9 +15,6 @@ Components.utils.import('resource://test/Utils.jsm');
|
|||
define("test/source-map/test-source-map-generator", ["require", "exports", "module"], function (require, exports, module) {
|
||||
|
||||
var SourceMapGenerator = require('source-map/source-map-generator').SourceMapGenerator;
|
||||
var SourceMapConsumer = require('source-map/source-map-consumer').SourceMapConsumer;
|
||||
var SourceNode = require('source-map/source-node').SourceNode;
|
||||
var util = require('source-map/util');
|
||||
|
||||
exports['test some simple stuff'] = function (assert, util) {
|
||||
var map = new SourceMapGenerator({
|
||||
|
@ -179,100 +176,19 @@ define("test/source-map/test-source-map-generator", ["require", "exports", "modu
|
|||
|
||||
map = JSON.parse(map.toString());
|
||||
|
||||
util.assertEqualMaps(assert, map, util.testMap);
|
||||
};
|
||||
|
||||
exports['test that source content can be set'] = function (assert, util) {
|
||||
var map = new SourceMapGenerator({
|
||||
file: 'min.js',
|
||||
sourceRoot: '/the/root'
|
||||
});
|
||||
map.addMapping({
|
||||
generated: { line: 1, column: 1 },
|
||||
original: { line: 1, column: 1 },
|
||||
source: 'one.js'
|
||||
});
|
||||
map.addMapping({
|
||||
generated: { line: 2, column: 1 },
|
||||
original: { line: 1, column: 1 },
|
||||
source: 'two.js'
|
||||
});
|
||||
map.setSourceContent('one.js', 'one file content');
|
||||
|
||||
map = JSON.parse(map.toString());
|
||||
assert.equal(map.version, 3);
|
||||
assert.equal(map.file, 'min.js');
|
||||
assert.equal(map.names.length, 3);
|
||||
assert.equal(map.names[0], 'bar');
|
||||
assert.equal(map.names[1], 'baz');
|
||||
assert.equal(map.names[2], 'n');
|
||||
assert.equal(map.sources.length, 2);
|
||||
assert.equal(map.sources[0], 'one.js');
|
||||
assert.equal(map.sources[1], 'two.js');
|
||||
assert.equal(map.sourcesContent[0], 'one file content');
|
||||
assert.equal(map.sourcesContent[1], null);
|
||||
assert.equal(map.sourceRoot, '/the/root');
|
||||
assert.equal(map.mappings, 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA');
|
||||
};
|
||||
|
||||
exports['test .fromSourceMap'] = function (assert, util) {
|
||||
var map = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(util.testMap));
|
||||
util.assertEqualMaps(assert, map.toJSON(), util.testMap);
|
||||
};
|
||||
|
||||
exports['test .fromSourceMap with sourcesContent'] = function (assert, util) {
|
||||
var map = SourceMapGenerator.fromSourceMap(
|
||||
new SourceMapConsumer(util.testMapWithSourcesContent));
|
||||
util.assertEqualMaps(assert, map.toJSON(), util.testMapWithSourcesContent);
|
||||
};
|
||||
|
||||
exports['test applySourceMap'] = function (assert, util) {
|
||||
var node = new SourceNode(null, null, null, [
|
||||
new SourceNode(2, 0, 'fileX', 'lineX2\n'),
|
||||
'genA1\n',
|
||||
new SourceNode(2, 0, 'fileY', 'lineY2\n'),
|
||||
'genA2\n',
|
||||
new SourceNode(1, 0, 'fileX', 'lineX1\n'),
|
||||
'genA3\n',
|
||||
new SourceNode(1, 0, 'fileY', 'lineY1\n')
|
||||
]);
|
||||
var mapStep1 = node.toStringWithSourceMap({
|
||||
file: 'fileA'
|
||||
}).map;
|
||||
mapStep1.setSourceContent('fileX', 'lineX1\nlineX2\n');
|
||||
mapStep1 = mapStep1.toJSON();
|
||||
|
||||
node = new SourceNode(null, null, null, [
|
||||
'gen1\n',
|
||||
new SourceNode(1, 0, 'fileA', 'lineA1\n'),
|
||||
new SourceNode(2, 0, 'fileA', 'lineA2\n'),
|
||||
new SourceNode(3, 0, 'fileA', 'lineA3\n'),
|
||||
new SourceNode(4, 0, 'fileA', 'lineA4\n'),
|
||||
new SourceNode(1, 0, 'fileB', 'lineB1\n'),
|
||||
new SourceNode(2, 0, 'fileB', 'lineB2\n'),
|
||||
'gen2\n'
|
||||
]);
|
||||
var mapStep2 = node.toStringWithSourceMap({
|
||||
file: 'fileGen'
|
||||
}).map;
|
||||
mapStep2.setSourceContent('fileB', 'lineB1\nlineB2\n');
|
||||
mapStep2 = mapStep2.toJSON();
|
||||
|
||||
node = new SourceNode(null, null, null, [
|
||||
'gen1\n',
|
||||
new SourceNode(2, 0, 'fileX', 'lineA1\n'),
|
||||
new SourceNode(2, 0, 'fileA', 'lineA2\n'),
|
||||
new SourceNode(2, 0, 'fileY', 'lineA3\n'),
|
||||
new SourceNode(4, 0, 'fileA', 'lineA4\n'),
|
||||
new SourceNode(1, 0, 'fileB', 'lineB1\n'),
|
||||
new SourceNode(2, 0, 'fileB', 'lineB2\n'),
|
||||
'gen2\n'
|
||||
]);
|
||||
var expectedMap = node.toStringWithSourceMap({
|
||||
file: 'fileGen'
|
||||
}).map;
|
||||
expectedMap.setSourceContent('fileX', 'lineX1\nlineX2\n');
|
||||
expectedMap.setSourceContent('fileB', 'lineB1\nlineB2\n');
|
||||
expectedMap = expectedMap.toJSON();
|
||||
|
||||
// apply source map "mapStep1" to "mapStep2"
|
||||
var generator = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(mapStep2));
|
||||
generator.applySourceMap(new SourceMapConsumer(mapStep1));
|
||||
var actualMap = generator.toJSON();
|
||||
|
||||
util.assertEqualMaps(assert, actualMap, expectedMap);
|
||||
};
|
||||
});
|
||||
function run_test() {
|
||||
runSourceMapTests('test/source-map/test-source-map-generator', do_throw);
|
||||
|
|
|
@ -136,10 +136,7 @@ define("test/source-map/test-source-node", ["require", "exports", "module"], fun
|
|||
exports['test .toStringWithSourceMap()'] = function (assert, util) {
|
||||
var node = new SourceNode(null, null, null,
|
||||
['(function () {\n',
|
||||
' ',
|
||||
new SourceNode(1, 0, 'a.js', 'someCall', 'originalCall'),
|
||||
new SourceNode(1, 8, 'a.js', '()'),
|
||||
';\n',
|
||||
' ', new SourceNode(1, 0, 'a.js', ['someCall()']), ';\n',
|
||||
' ', new SourceNode(2, 0, 'b.js', ['if (foo) bar()']), ';\n',
|
||||
'}());']);
|
||||
var map = node.toStringWithSourceMap({
|
||||
|
@ -151,14 +148,6 @@ define("test/source-map/test-source-node", ["require", "exports", "module"], fun
|
|||
|
||||
var actual;
|
||||
|
||||
actual = map.originalPositionFor({
|
||||
line: 1,
|
||||
column: 4
|
||||
});
|
||||
assert.equal(actual.source, null);
|
||||
assert.equal(actual.line, null);
|
||||
assert.equal(actual.column, null);
|
||||
|
||||
actual = map.originalPositionFor({
|
||||
line: 2,
|
||||
column: 2
|
||||
|
@ -166,7 +155,6 @@ define("test/source-map/test-source-node", ["require", "exports", "module"], fun
|
|||
assert.equal(actual.source, 'a.js');
|
||||
assert.equal(actual.line, 1);
|
||||
assert.equal(actual.column, 0);
|
||||
assert.equal(actual.name, 'originalCall');
|
||||
|
||||
actual = map.originalPositionFor({
|
||||
line: 3,
|
||||
|
@ -175,115 +163,8 @@ define("test/source-map/test-source-node", ["require", "exports", "module"], fun
|
|||
assert.equal(actual.source, 'b.js');
|
||||
assert.equal(actual.line, 2);
|
||||
assert.equal(actual.column, 0);
|
||||
|
||||
actual = map.originalPositionFor({
|
||||
line: 3,
|
||||
column: 16
|
||||
});
|
||||
assert.equal(actual.source, null);
|
||||
assert.equal(actual.line, null);
|
||||
assert.equal(actual.column, null);
|
||||
|
||||
actual = map.originalPositionFor({
|
||||
line: 4,
|
||||
column: 2
|
||||
});
|
||||
assert.equal(actual.source, null);
|
||||
assert.equal(actual.line, null);
|
||||
assert.equal(actual.column, null);
|
||||
};
|
||||
|
||||
exports['test .fromStringWithSourceMap()'] = function (assert, util) {
|
||||
var node = SourceNode.fromStringWithSourceMap(
|
||||
util.testGeneratedCode,
|
||||
new SourceMapConsumer(util.testMap));
|
||||
|
||||
var result = node.toStringWithSourceMap({
|
||||
file: 'min.js'
|
||||
});
|
||||
var map = result.map;
|
||||
var code = result.code;
|
||||
|
||||
assert.equal(code, util.testGeneratedCode);
|
||||
assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator');
|
||||
map = map.toJSON();
|
||||
assert.equal(map.version, util.testMap.version);
|
||||
assert.equal(map.file, util.testMap.file);
|
||||
assert.equal(map.mappings, util.testMap.mappings);
|
||||
};
|
||||
|
||||
exports['test .fromStringWithSourceMap() complex version'] = function (assert, util) {
|
||||
var input = new SourceNode(null, null, null, [
|
||||
"(function() {\n",
|
||||
" var Test = {};\n",
|
||||
" ", new SourceNode(1, 0, "a.js", "Test.A = { value: 1234 };\n"),
|
||||
" ", new SourceNode(2, 0, "a.js", "Test.A.x = 'xyz';"), "\n",
|
||||
"}());\n",
|
||||
"/* Generated Source */"]);
|
||||
input = input.toStringWithSourceMap({
|
||||
file: 'foo.js'
|
||||
});
|
||||
|
||||
var node = SourceNode.fromStringWithSourceMap(
|
||||
input.code,
|
||||
new SourceMapConsumer(input.map.toString()));
|
||||
|
||||
var result = node.toStringWithSourceMap({
|
||||
file: 'foo.js'
|
||||
});
|
||||
var map = result.map;
|
||||
var code = result.code;
|
||||
|
||||
assert.equal(code, input.code);
|
||||
assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator');
|
||||
map = map.toJSON();
|
||||
var inputMap = input.map.toJSON();
|
||||
util.assertEqualMaps(assert, map, inputMap);
|
||||
};
|
||||
|
||||
exports['test setSourceContent with toStringWithSourceMap'] = function (assert, util) {
|
||||
var aNode = new SourceNode(1, 1, 'a.js', 'a');
|
||||
aNode.setSourceContent('a.js', 'someContent');
|
||||
var node = new SourceNode(null, null, null,
|
||||
['(function () {\n',
|
||||
' ', aNode,
|
||||
' ', new SourceNode(1, 1, 'b.js', 'b'),
|
||||
'}());']);
|
||||
node.setSourceContent('b.js', 'otherContent');
|
||||
var map = node.toStringWithSourceMap({
|
||||
file: 'foo.js'
|
||||
}).map;
|
||||
|
||||
assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator');
|
||||
map = new SourceMapConsumer(map.toString());
|
||||
|
||||
assert.equal(map.sources.length, 2);
|
||||
assert.equal(map.sources[0], 'a.js');
|
||||
assert.equal(map.sources[1], 'b.js');
|
||||
assert.equal(map.sourcesContent.length, 2);
|
||||
assert.equal(map.sourcesContent[0], 'someContent');
|
||||
assert.equal(map.sourcesContent[1], 'otherContent');
|
||||
};
|
||||
|
||||
exports['test walkSourceContents'] = function (assert, util) {
|
||||
var aNode = new SourceNode(1, 1, 'a.js', 'a');
|
||||
aNode.setSourceContent('a.js', 'someContent');
|
||||
var node = new SourceNode(null, null, null,
|
||||
['(function () {\n',
|
||||
' ', aNode,
|
||||
' ', new SourceNode(1, 1, 'b.js', 'b'),
|
||||
'}());']);
|
||||
node.setSourceContent('b.js', 'otherContent');
|
||||
var results = [];
|
||||
node.walkSourceContents(function (sourceFile, sourceContent) {
|
||||
results.push([sourceFile, sourceContent]);
|
||||
});
|
||||
assert.equal(results.length, 2);
|
||||
assert.equal(results[0][0], 'a.js');
|
||||
assert.equal(results[0][1], 'someContent');
|
||||
assert.equal(results[1][0], 'b.js');
|
||||
assert.equal(results[1][1], 'otherContent');
|
||||
};
|
||||
});
|
||||
function run_test() {
|
||||
runSourceMapTests('test/source-map/test-source-node', do_throw);
|
||||
|
|
Загрузка…
Ссылка в новой задаче