Backout eb887b962dfa (bug 772119) on suspicion of leaks

This commit is contained in:
Panos Astithas 2013-04-10 16:08:59 +03:00
Родитель 116a5ab638
Коммит 2c8dec2f1f
32 изменённых файлов: 390 добавлений и 2053 удалений

Просмотреть файл

@ -1060,7 +1060,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);

Просмотреть файл

@ -261,8 +261,6 @@ let DebuggerController = {
if (aCallback) {
aCallback();
}
}, {
useSourceMaps: Services.prefs.getBoolPref("devtools.debugger.source-maps-enabled")
});
});
},
@ -1114,7 +1112,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;
}

Просмотреть файл

@ -96,7 +96,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)
@ -128,10 +127,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);
}
}

Просмотреть файл

@ -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;
}
@ -470,7 +460,7 @@ DebuggerClient.prototype = {
? aPacket
: this.compat.onPacket(aPacket);
resolve(packet).then((aPacket) => {
resolve(packet).then(function (aPacket) {
if (!this._connected) {
// Hello packet.
this._connected = 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 + "\n" + ex.stack);
}
this._sendRequests();
}, 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 +
@ -288,14 +268,6 @@ ThreadActor.prototype = {
* Handle a protocol request to resume execution of the debuggee.
*/
onResume: function TA_onResume(aRequest) {
if (this._state !== "paused") {
return {
error: "wrongState",
message: "Can't resume when debuggee isn't paused. Current state is '"
+ this._state + "'"
};
}
// In case of multiple nested event loops (due to multiple debuggers open in
// different tabs or multiple debugger clients connected to the same tab)
// only allow resumption in a LIFO order.
@ -467,23 +439,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) {
@ -516,58 +479,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);
},
/**
@ -678,16 +608,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)]
};
},
/**
@ -724,8 +655,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() };
}
},
@ -796,6 +727,7 @@ ThreadActor.prototype = {
if (aFrame) {
packet.frame = this._createFrameActor(aFrame).form();
}
if (poppedFrames) {
packet.poppedFrames = poppedFrames;
}
@ -1101,9 +1033,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 = {};
}
@ -1163,7 +1094,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;
@ -1183,14 +1114,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.
@ -1199,7 +1122,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;
@ -1223,30 +1146,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;
},
/**
@ -1294,6 +1215,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 = {
@ -1400,7 +1363,6 @@ SourceActor.prototype = {
actorPrefix: "source",
get threadActor() { return this._threadActor; },
get url() { return this._url; },
form: function SA_form() {
return {
@ -1420,9 +1382,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) {
@ -1431,17 +1394,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 = {
@ -2028,14 +2095,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);
},
/**
@ -2357,183 +2417,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.
/**
@ -2554,126 +2437,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,9 +26,6 @@ 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) {
@ -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));
},
/**

Просмотреть файл

@ -111,7 +111,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);
});
}
@ -147,7 +147,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 + ")");
});
}));
@ -155,13 +161,9 @@ function test_profiler_status()
var profiler = aResponse.profilerActor;
do_check_false(Profiler.IsActive());
client.request({
to: profiler,
type: "startProfiler",
features: []
}, (aResponse) => {
client.request({ to: profiler, type: "startProfiler", features: [] }, (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);