@@ -109,6 +109,30 @@ functions body
script.js
* `clearBreakpoint`, `cb(...)` - Clear breakpoint

It is also possible to set a breakpoint in a file (module) that
isn't loaded yet:

% ./node debug test/fixtures/break-in-module/main.js
< debugger listening on port 5858
connecting to port 5858... ok
break in test/fixtures/break-in-module/main.js:1
1 var mod = require('./mod.js');
2 mod.hello();
3 mod.hello();
debug> setBreakpoint('mod.js', 23)
Warning: script 'mod.js' was not loaded yet.
1 var mod = require('./mod.js');
2 mod.hello();
3 mod.hello();
debug> c
break in test/fixtures/break-in-module/mod.js:23
21
22 exports.hello = function() {
23 return 'hello from module';
24 };
25
debug>

### Info

* `backtrace`, `bt` - Print backtrace of current execution frame
@@ -1385,16 +1385,28 @@ Interface.prototype.setBreakpoint = function(script, line,
scriptId = script;
}

if (!scriptId) return this.error('Script : ' + script + ' not found');
if (ambiguous) return this.error('Script name is ambiguous');
if (line <= 0) return this.error('Line should be a positive value');

var req = {
type: 'scriptId',
target: scriptId,
line: line - 1,
condition: condition
};
var req;
if (scriptId) {
req = {
type: 'scriptId',
target: scriptId,
line: line - 1,
condition: condition
};
} else {
this.print('Warning: script \'' + script + '\' was not loaded yet.');
var escapedPath = script.replace(/([/\\.?*()^${}|[\]])/g, '\\$1');
var scriptPathRegex = '^(.*[\\/\\\\])?' + escapedPath + '$';
req = {
type: 'scriptRegExp',
target: scriptPathRegex,
line: line - 1,
condition: condition
};
}
}

self.pause();
@@ -1411,20 +1423,18 @@ Interface.prototype.setBreakpoint = function(script, line,
// Try load scriptId and line from response
if (!scriptId) {
scriptId = res.script_id;
line = res.line;
}

// If we finally have one - remember this breakpoint
if (scriptId) {
self.client.breakpoints.push({
id: res.breakpoint,
scriptId: scriptId,
script: (self.client.scripts[scriptId] || {}).name,
line: line,
condition: condition
});
line = res.line + 1;
}

// Remember this breakpoint even if scriptId is not resolved yet
self.client.breakpoints.push({
id: res.breakpoint,
scriptId: scriptId,
script: (self.client.scripts[scriptId] || {}).name,
line: line,
condition: condition,
scriptReq: script
});
}
self.resume();
});
@@ -1439,7 +1449,9 @@ Interface.prototype.clearBreakpoint = function(script, line) {
index;

this.client.breakpoints.some(function(bp, i) {
if (bp.scriptId === script || bp.script.indexOf(script) !== -1) {
if (bp.scriptId === script ||
bp.scriptReq === script ||
(bp.script && bp.script.indexOf(script) !== -1)) {
if (index !== undefined) {
ambiguous = true;
}
@@ -1657,7 +1669,8 @@ Interface.prototype.trySpawn = function(cb) {

// Restore breakpoints
breakpoints.forEach(function(bp) {
self.setBreakpoint(bp.scriptId, bp.line, bp.condition, true);
self.print('Restoring breakpoint ' + bp.scriptReq + ':' + bp.line);
self.setBreakpoint(bp.scriptReq, bp.line, bp.condition, true);
});

client.on('close', function() {
@@ -0,0 +1,4 @@
var mod = require('./mod.js');
mod.hello();
mod.hello();
debugger;
@@ -0,0 +1,24 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

exports.hello = function() {
return 'hello from module';
};
@@ -126,16 +126,23 @@ function addTest(input, output) {
expected.push({input: input, lines: output, callback: next});
}

var initialLines = [
var handshakeLines = [
/listening on port \d+/,
/connecting.* ok/,
/connecting.* ok/
];

var initialBreakLines = [
/break in .*:1/,
/1/, /2/, /3/
];

var initialLines = handshakeLines.concat(initialBreakLines);

// Process initial lines
addTest(null, initialLines);

exports.startDebugger = startDebugger;
exports.addTest = addTest;
exports.initialLines = initialLines;
exports.handshakeLines = handshakeLines;
exports.initialBreakLines = initialBreakLines;
@@ -0,0 +1,80 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var repl = require('./helper-debugger-repl.js');

repl.startDebugger('break-in-module/main.js');

// -- SET BREAKPOINT --

// Set breakpoint by file name + line number where the file is not loaded yet
repl.addTest('sb("mod.js", 23)', [
/Warning: script 'mod\.js' was not loaded yet\./,
/1/, /2/, /3/, /4/, /5/, /6/
]);

// Check escaping of regex characters
repl.addTest('sb(")^$*+?}{|][(.js\\\\", 1)', [
/Warning: script '[^']+' was not loaded yet\./,
/1/, /2/, /3/, /4/, /5/, /6/
]);

// continue - the breakpoint should be triggered
repl.addTest('c', [
/break in .*[\\\/]mod\.js:23/,
/21/, /22/, /23/, /24/, /25/
]);

// -- RESTORE BREAKPOINT ON RESTART --

// Restart the application - breakpoint should be restored
repl.addTest('restart', [].concat(
[
/terminated/
],
repl.handshakeLines,
[
/Restoring breakpoint mod.js:23/,
/Warning: script 'mod\.js' was not loaded yet\./,
/Restoring breakpoint \).*:\d+/,
/Warning: script '\)[^']*' was not loaded yet\./
],
repl.initialBreakLines));

// continue - the breakpoint should be triggered
repl.addTest('c', [
/break in .*[\\\/]mod\.js:23/,
/21/, /22/, /23/, /24/, /25/
]);

// -- CLEAR BREAKPOINT SET IN MODULE TO BE LOADED --

repl.addTest('cb("mod.js", 23)', [
/18/, /./, /./, /./, /./, /./, /./, /./, /26/
]);

repl.addTest('c', [
/break in .*[\\\/]main\.js:4/,
/2/, /3/, /4/, /5/, /6/
]);

// -- (END) --
repl.addTest('quit', []);