diff --git a/deps/node-inspect/CHANGELOG.md b/deps/node-inspect/CHANGELOG.md index 0a7ba1be94fb50..dc217a5ba2d564 100644 --- a/deps/node-inspect/CHANGELOG.md +++ b/deps/node-inspect/CHANGELOG.md @@ -1,3 +1,30 @@ +### 1.10.6 + +* chore: Fix usage text for embedded mode - **[@addaleax](https://github.com/addaleax)** [#20](https://github.com/nodejs/node-inspect/pull/20) + - [`b0779f5`](https://github.com/nodejs/node-inspect/commit/b0779f597104e9ada5681f64d7e714525b753511) **chore:** Fix usage text for embedded mode +* print 'ok' after connection - **[@ofrobots](https://github.com/ofrobots)** [#25](https://github.com/nodejs/node-inspect/pull/25) + - [`2a47125`](https://github.com/nodejs/node-inspect/commit/2a4712577f6996fbb078dcfcd7320c397685d76a) **fix:** print 'ok' after connection +* Make autocompletion in REPL work - **[@aqrln](https://github.com/aqrln)** [#28](https://github.com/nodejs/node-inspect/pull/28) + - [`ccab737`](https://github.com/nodejs/node-inspect/commit/ccab737399249a8c2230ed6adfec579c7d724364) **fix:** Make autocompletion in REPL work +* Remove console.error() statement - **[@aqrln](https://github.com/aqrln)** [#30](https://github.com/nodejs/node-inspect/pull/30) + - [`032b045`](https://github.com/nodejs/node-inspect/commit/032b045d4d73622c77b7ebcc26781c6ad98200b3) **style:** Remove console.error() statement +* Take --debug-port into account - **[@jkrems](https://github.com/jkrems)** [#26](https://github.com/nodejs/node-inspect/pull/26) + - [`054d4b1`](https://github.com/nodejs/node-inspect/commit/054d4b10e65f12a3a4b10b4c0ab2a4768cc5e893) **fix:** Take --debug-port into account +* Delay run until breakpoints are restored - **[@jkrems](https://github.com/jkrems)** [#34](https://github.com/nodejs/node-inspect/pull/34) + - [`802b88c`](https://github.com/nodejs/node-inspect/commit/802b88c8ad0a57608cb9e0cb4bf46ed683bb6344) **fix:** Delay run until breakpoints are restored + - [`2b93173`](https://github.com/nodejs/node-inspect/commit/2b93173d95e7f8b30d85603613cb2ae3b3ec18db) **fix:** Use single string for paused notice + - [`b4d5ee2`](https://github.com/nodejs/node-inspect/commit/b4d5ee2a3d25613b35a2e8e10a0eb75582cc5654) **fix:** Work around inconsistent handling of strict directive + - [`f6ccfc7`](https://github.com/nodejs/node-inspect/commit/f6ccfc7f4d00ad4fdf3b581b677f8d7f1699c44c) **fix:** Only restart after port is free + - [`8b101bf`](https://github.com/nodejs/node-inspect/commit/8b101bf669ca102df4980bfad3e0436ef1c2f1a4) **test:** Skip exact match on AIX +* [`a4e4b6f`](https://github.com/nodejs/node-inspect/commit/a4e4b6feeba4dedfd2c89ef32f39e813314d3bbd) **chore:** Fix repo info in package.json + + +### 1.10.5 + +* docs: minor edits to governance docs - **[@joshgav](https://github.com/joshgav)** [#17](https://github.com/buggerjs/node-inspect/pull/17) + - [`a70fe04`](https://github.com/buggerjs/node-inspect/commit/a70fe04bdde9b7c74588685066291f9b11183328) **docs:** minor edits to governance docs + + ### 1.10.4 * [`1c31bf7`](https://github.com/buggerjs/node-inspect/commit/1c31bf7d1b3ea1b424ae0662526596670cb506c9) **chore:** Support embedded mode diff --git a/deps/node-inspect/CONTRIBUTING.md b/deps/node-inspect/CONTRIBUTING.md index 08d333cce8321f..012d29471462de 100644 --- a/deps/node-inspect/CONTRIBUTING.md +++ b/deps/node-inspect/CONTRIBUTING.md @@ -4,8 +4,7 @@ This document outlines some of the practices we care about. If you have any questions or suggestions about the process, -feel free to [open an issue](#reporting-issues) -. +feel free to [open an issue](#reporting-issues). ## Code of Conduct @@ -13,11 +12,10 @@ The [Node.js Code of Conduct][] applies to this repo. [Node.js Code of Conduct]: https://github.com/nodejs/node/blob/master/CODE_OF_CONDUCT.md -## Code Contributions +## Governance -The nodereport project falls under the governance of the diagnostics -working group which is documented in: -https://github.com/nodejs/diagnostics/blob/master/GOVERNANCE.md. +This project falls under the governance of the Node.js Diagnostics WG as +described at . ## Developer's Certificate of Origin 1.1 @@ -51,7 +49,7 @@ By making a contribution to this project, I certify that: If you find any mistakes in the docs or a bug in the code, please [open an issue in Github](https://github.com/nodejs/node-inspect/issues/new) so we can look into it. -You can also [create a PR](#contributing-code) fixing it yourself, or course. +You can also [create a PR](#contributing-code) fixing it yourself of course. If you report a bug, please follow these guidelines: @@ -67,7 +65,7 @@ If you report a bug, please follow these guidelines: For small documentation changes, you can use [Github's editing feature](https://help.github.com/articles/editing-files-in-another-user-s-repository/). The only thing to keep in mind is to prefix the commit message with "docs: ". -The detault commit message generated by Github will lead to a failing CI build. +The default commit message generated by Github will lead to a failing CI build. For larger updates to the documentation it might be better to follow the [instructions for contributing code below](#contributing-code). diff --git a/deps/node-inspect/GOVERNANCE.md b/deps/node-inspect/GOVERNANCE.md index 238c1b825837ac..20e333a247cbfd 100644 --- a/deps/node-inspect/GOVERNANCE.md +++ b/deps/node-inspect/GOVERNANCE.md @@ -1,5 +1,4 @@ # node-inspect Project Governance -The node-inspect project falls under the governance of the diagnostics -working group which is documented in: -https://github.com/nodejs/diagnostics/blob/master/GOVERNANCE.md. +The node-inspect project is governed by the Node.js Diagnostics WG as described +at . diff --git a/deps/node-inspect/examples/alive.js b/deps/node-inspect/examples/alive.js index 3cf557b053981e..c8ad157b452d11 100644 --- a/deps/node-inspect/examples/alive.js +++ b/deps/node-inspect/examples/alive.js @@ -1,4 +1,3 @@ -'use strict'; let x = 0; function heartbeat() { ++x; diff --git a/deps/node-inspect/examples/backtrace.js b/deps/node-inspect/examples/backtrace.js index f5d71a14f96f86..f18b33ea5584b2 100644 --- a/deps/node-inspect/examples/backtrace.js +++ b/deps/node-inspect/examples/backtrace.js @@ -1,4 +1,3 @@ -'use strict'; const { exports: moduleScoped } = module; function topFn(a, b = false) { diff --git a/deps/node-inspect/examples/cjs/index.js b/deps/node-inspect/examples/cjs/index.js index d5815e865999f7..0ace6d9b78591c 100644 --- a/deps/node-inspect/examples/cjs/index.js +++ b/deps/node-inspect/examples/cjs/index.js @@ -1,5 +1,5 @@ -'use strict'; +const fourty = 40; const { add } = require('./other'); -const sum = add(40, 2); +const sum = add(fourty, 2); module.exports = sum; diff --git a/deps/node-inspect/examples/cjs/other.js b/deps/node-inspect/examples/cjs/other.js index efadaa18d26e6d..44a9a439bab987 100644 --- a/deps/node-inspect/examples/cjs/other.js +++ b/deps/node-inspect/examples/cjs/other.js @@ -1,4 +1,3 @@ -'use strict'; exports.add = function add(a, b) { return a + b; }; diff --git a/deps/node-inspect/examples/exceptions.js b/deps/node-inspect/examples/exceptions.js index 00c48ed31b5113..f57d48a48dffc8 100644 --- a/deps/node-inspect/examples/exceptions.js +++ b/deps/node-inspect/examples/exceptions.js @@ -1,4 +1,3 @@ -'use strict'; let error = null; try { throw new Error('Caught'); diff --git a/deps/node-inspect/examples/three-lines.js b/deps/node-inspect/examples/three-lines.js index 4e1cb95d1130b8..c17c7c1ddcfe58 100644 --- a/deps/node-inspect/examples/three-lines.js +++ b/deps/node-inspect/examples/three-lines.js @@ -1,4 +1,3 @@ -'use strict'; let x = 1; x = x + 1; module.exports = x; diff --git a/deps/node-inspect/examples/use-strict.js b/deps/node-inspect/examples/use-strict.js new file mode 100644 index 00000000000000..9fe4b8f3b42f57 --- /dev/null +++ b/deps/node-inspect/examples/use-strict.js @@ -0,0 +1,2 @@ +'use strict'; +console.log('first real line'); diff --git a/deps/node-inspect/lib/_inspect.js b/deps/node-inspect/lib/_inspect.js index 5cd1cc2d685a90..ac32e0a6a432fa 100644 --- a/deps/node-inspect/lib/_inspect.js +++ b/deps/node-inspect/lib/_inspect.js @@ -22,10 +22,13 @@ 'use strict'; const { spawn } = require('child_process'); const { EventEmitter } = require('events'); +const net = require('net'); const util = require('util'); +const runAsStandalone = typeof __dirname !== 'undefined'; + const [ InspectClient, createRepl ] = - (typeof __dirname !== 'undefined') ? + runAsStandalone ? // This copy of node-inspect is on-disk, relative paths make sense. [ require('./internal/inspect_client'), @@ -39,7 +42,16 @@ const [ InspectClient, createRepl ] = const debuglog = util.debuglog('inspect'); -exports.port = 9229; +const DEBUG_PORT_PATTERN = /^--(?:debug|inspect)-port=(\d+)$/; +function getDefaultPort() { + for (const arg of process.execArgv) { + const match = arg.match(DEBUG_PORT_PATTERN); + if (match) { + return +match[1]; + } + } + return 9229; +} function runScript(script, scriptArgs, inspectPort, childPrint) { return new Promise((resolve) => { @@ -88,6 +100,45 @@ function createAgentProxy(domain, client) { }); } +function portIsFree(host, port, timeout = 2000) { + const retryDelay = 150; + let didTimeOut = false; + + return new Promise((resolve, reject) => { + setTimeout(() => { + didTimeOut = true; + reject(new Error( + `Timeout (${timeout}) waiting for ${host}:${port} to be free`)); + }, timeout); + + function pingPort() { + if (didTimeOut) return; + + const socket = net.connect(port, host); + let didRetry = false; + function retry() { + if (!didRetry && !didTimeOut) { + didRetry = true; + setTimeout(pingPort, retryDelay); + } + } + + socket.on('error', (error) => { + if (error.code === 'ECONNREFUSED') { + resolve(); + } else { + retry(); + } + }); + socket.on('connect', () => { + socket.destroy(); + retry(); + }); + } + pingPort(); + }); +} + class NodeInspector { constructor(options, stdin, stdout) { this.options = options; @@ -128,8 +179,9 @@ class NodeInspector { process.once('SIGHUP', process.exit.bind(process, 0)); this.run() - .then(() => { - this.repl = startRepl(); + .then(() => startRepl()) + .then((repl) => { + this.repl = repl; this.repl.on('exit', () => { process.exit(0); }); @@ -139,15 +191,19 @@ class NodeInspector { } suspendReplWhile(fn) { - this.repl.rli.pause(); + if (this.repl) { + this.repl.rli.pause(); + } this.stdin.pause(); this.paused = true; return new Promise((resolve) => { resolve(fn()); }).then(() => { this.paused = false; - this.repl.rli.resume(); - this.repl.displayPrompt(); + if (this.repl) { + this.repl.rli.resume(); + this.repl.displayPrompt(); + } this.stdin.resume(); }).then(null, (error) => process.nextTick(() => { throw error; })); } @@ -162,7 +218,14 @@ class NodeInspector { run() { this.killChild(); - return this._runScript().then((child) => { + const { host, port } = this.options; + + const runOncePortIsFree = () => { + return portIsFree(host, port) + .then(() => this._runScript()); + }; + + return runOncePortIsFree().then((child) => { this.child = child; let connectionAttempts = 0; @@ -173,6 +236,7 @@ class NodeInspector { return this.client.connect() .then(() => { debuglog('connection established'); + this.stdout.write(' ok'); }, (error) => { debuglog('connect failed', error); // If it's failed to connect 10 times then print failed message @@ -186,7 +250,6 @@ class NodeInspector { }); }; - const { host, port } = this.options; this.print(`connecting to ${host}:${port} ..`, true); return attemptConnect(); }); @@ -225,7 +288,7 @@ class NodeInspector { function parseArgv([target, ...args]) { let host = '127.0.0.1'; - let port = exports.port; + let port = getDefaultPort(); let isRemote = false; let script = target; let scriptArgs = args; @@ -258,8 +321,12 @@ function startInspect(argv = process.argv.slice(2), stdout = process.stdout) { /* eslint-disable no-console */ if (argv.length < 1) { - console.error('Usage: node-inspect script.js'); - console.error(' node-inspect :'); + const invokedAs = runAsStandalone ? + 'node-inspect' : + `${process.argv0} ${process.argv[1]}`; + + console.error(`Usage: ${invokedAs} script.js`); + console.error(` ${invokedAs} :`); process.exit(1); } diff --git a/deps/node-inspect/lib/internal/inspect_client.js b/deps/node-inspect/lib/internal/inspect_client.js index d5ce46db05c37d..c247e2add87706 100644 --- a/deps/node-inspect/lib/internal/inspect_client.js +++ b/deps/node-inspect/lib/internal/inspect_client.js @@ -334,20 +334,7 @@ class Client extends EventEmitter { this.emit('close'); }); - Promise.all([ - this.callMethod('Runtime.enable'), - this.callMethod('Debugger.enable'), - this.callMethod('Debugger.setPauseOnExceptions', { state: 'none' }), - this.callMethod('Debugger.setAsyncCallStackDepth', { maxDepth: 0 }), - this.callMethod('Profiler.enable'), - this.callMethod('Profiler.setSamplingInterval', { interval: 100 }), - this.callMethod('Debugger.setBlackboxPatterns', { patterns: [] }), - this.callMethod('Runtime.runIfWaitingForDebugger'), - ]).then(() => { - this.emit('ready'); - }, (error) => { - this.emit('error', error); - }); + this.emit('ready'); }; return new Promise((resolve, reject) => { diff --git a/deps/node-inspect/lib/internal/inspect_repl.js b/deps/node-inspect/lib/internal/inspect_repl.js index c61bbc9fb8e05a..2de86b247bb4b1 100644 --- a/deps/node-inspect/lib/internal/inspect_repl.js +++ b/deps/node-inspect/lib/internal/inspect_repl.js @@ -234,10 +234,10 @@ class ScopeSnapshot { constructor(scope, properties) { Object.assign(this, scope); this.properties = new Map(properties.map((prop) => { - // console.error(prop); const value = new RemoteObject(prop.value); return [prop.name, value]; })); + this.completionGroup = properties.map((prop) => prop.name); } [util.inspect.custom](depth, opts) { @@ -480,7 +480,9 @@ function createRepl(inspector) { if (!selectedFrame) { return Promise.reject(new Error('Requires execution to be paused')); } - return selectedFrame.loadScopes(); + return selectedFrame.loadScopes().then((scopes) => { + return scopes.map((scope) => scope.completionGroup); + }); } if (selectedFrame) { @@ -746,8 +748,8 @@ function createRepl(inspector) { .filter(({ location }) => !!location.scriptUrl) .map(({ location }) => setBreakpoint(location.scriptUrl, location.lineNumber + 1)); - if (!newBreakpoints.length) return; - Promise.all(newBreakpoints).then((results) => { + if (!newBreakpoints.length) return Promise.resolve(); + return Promise.all(newBreakpoints).then((results) => { print(`${results.length} breakpoints restored.`); }); } @@ -768,7 +770,8 @@ function createRepl(inspector) { const breakType = reason === 'other' ? 'break' : reason; const script = knownScripts[scriptId]; const scriptUrl = script ? getRelativePath(script.url) : '[unknown]'; - print(`${breakType} in ${scriptUrl}:${lineNumber + 1}`); + + const header = `${breakType} in ${scriptUrl}:${lineNumber + 1}`; inspector.suspendReplWhile(() => Promise.all([formatWatchers(true), selectedFrame.list(2)]) @@ -776,8 +779,10 @@ function createRepl(inspector) { if (watcherList) { return `${watcherList}\n${inspect(context)}`; } - return context; - }).then(print)); + return inspect(context); + }).then((breakContext) => { + print(`${header}\n${breakContext}`); + })); }); function handleResumed() { @@ -1024,7 +1029,30 @@ function createRepl(inspector) { aliasProperties(context, SHORTCUTS); } + function initAfterStart() { + const setupTasks = [ + Runtime.enable(), + Profiler.enable(), + Profiler.setSamplingInterval({ interval: 100 }), + Debugger.enable(), + Debugger.setPauseOnExceptions({ state: 'none' }), + Debugger.setAsyncCallStackDepth({ maxDepth: 0 }), + Debugger.setBlackboxPatterns({ patterns: [] }), + Debugger.setPauseOnExceptions({ state: pauseOnExceptionState }), + restoreBreakpoints(), + Runtime.runIfWaitingForDebugger(), + ]; + return Promise.all(setupTasks); + } + return function startRepl() { + inspector.client.on('close', () => { + resetOnStart(); + }); + inspector.client.on('ready', () => { + initAfterStart(); + }); + const replOptions = { prompt: 'debug> ', input: inspector.stdin, @@ -1033,6 +1061,7 @@ function createRepl(inspector) { useGlobal: false, ignoreUndefined: true, }; + repl = Repl.start(replOptions); // eslint-disable-line prefer-const initializeContext(repl.context); repl.on('reset', initializeContext); @@ -1042,14 +1071,8 @@ function createRepl(inspector) { repl.rli.emit('SIGINT'); }); - inspector.client.on('close', () => { - resetOnStart(); - }); - - inspector.client.on('ready', () => { - restoreBreakpoints(); - Debugger.setPauseOnExceptions({ state: pauseOnExceptionState }); - }); + // Init once for the initial connection + initAfterStart(); return repl; }; diff --git a/deps/node-inspect/package.json b/deps/node-inspect/package.json index f4b3aec6d94d5d..536a525e5c9bf5 100644 --- a/deps/node-inspect/package.json +++ b/deps/node-inspect/package.json @@ -1,17 +1,17 @@ { "name": "node-inspect", - "version": "1.10.4", + "version": "1.10.6", "description": "Node Inspect", "license": "MIT", "main": "lib/_inspect.js", "bin": "cli.js", - "homepage": "https://github.com/buggerjs/node-inspect", + "homepage": "https://github.com/nodejs/node-inspect", "repository": { "type": "git", - "url": "git+ssh://git@github.com/buggerjs/node-inspect" + "url": "git+ssh://git@github.com/nodejs/node-inspect" }, "bugs": { - "url": "https://github.com/buggerjs/node-inspect/issues" + "url": "https://github.com/nodejs/node-inspect/issues" }, "scripts": { "pretest": "eslint --rulesdir=tools/eslint-rules lib test", diff --git a/deps/node-inspect/test/cli/backtrace.test.js b/deps/node-inspect/test/cli/backtrace.test.js index 2e2ba4a3423360..9cd8a82a33f043 100644 --- a/deps/node-inspect/test/cli/backtrace.test.js +++ b/deps/node-inspect/test/cli/backtrace.test.js @@ -19,11 +19,11 @@ test('display and navigate backtrace', (t) => { .then(() => cli.stepCommand('c')) .then(() => cli.command('bt')) .then(() => { - t.match(cli.output, `#0 topFn ${script}:8:2`); + t.match(cli.output, `#0 topFn ${script}:7:2`); }) .then(() => cli.command('backtrace')) .then(() => { - t.match(cli.output, `#0 topFn ${script}:8:2`); + t.match(cli.output, `#0 topFn ${script}:7:2`); }) .then(() => cli.quit()) .then(null, onFatal); diff --git a/deps/node-inspect/test/cli/exceptions.test.js b/deps/node-inspect/test/cli/exceptions.test.js index 6d3ff68f057068..b66c09fc504424 100644 --- a/deps/node-inspect/test/cli/exceptions.test.js +++ b/deps/node-inspect/test/cli/exceptions.test.js @@ -31,11 +31,11 @@ test('break on (uncaught) exceptions', (t) => { .then(() => cli.command('breakOnException')) .then(() => cli.stepCommand('c')) .then(() => { - t.match(cli.output, `exception in ${script}:4`); + t.match(cli.output, `exception in ${script}:3`); }) .then(() => cli.stepCommand('c')) .then(() => { - t.match(cli.output, `exception in ${script}:10`); + t.match(cli.output, `exception in ${script}:9`); }) // Next run: With `breakOnUncaught` it only pauses on the 2nd exception @@ -46,7 +46,7 @@ test('break on (uncaught) exceptions', (t) => { }) .then(() => cli.stepCommand('c')) .then(() => { - t.match(cli.output, `exception in ${script}:10`); + t.match(cli.output, `exception in ${script}:9`); }) // Next run: Back to the initial state! It should die again. diff --git a/deps/node-inspect/test/cli/launch.test.js b/deps/node-inspect/test/cli/launch.test.js index 962197e84f2295..99c6ce0aa2efa1 100644 --- a/deps/node-inspect/test/cli/launch.test.js +++ b/deps/node-inspect/test/cli/launch.test.js @@ -8,7 +8,9 @@ const startCLI = require('./start-cli'); test('examples/empty.js', (t) => { const script = Path.join('examples', 'empty.js'); const cli = startCLI([script]); - return cli.waitForPrompt() + + return cli.waitFor(/break/) + .then(() => cli.waitForPrompt()) .then(() => { t.match(cli.output, 'debug>', 'prints a prompt'); t.match( diff --git a/deps/node-inspect/test/cli/preserve-breaks.test.js b/deps/node-inspect/test/cli/preserve-breaks.test.js index a248b3aa25605b..8de8227343626a 100644 --- a/deps/node-inspect/test/cli/preserve-breaks.test.js +++ b/deps/node-inspect/test/cli/preserve-breaks.test.js @@ -48,8 +48,17 @@ test('run after quit / restart', (t) => { }) .then(() => cli.command('breakpoints')) .then(() => { - t.match(cli.output, `#0 ${script}:2`); - t.match(cli.output, `#1 ${script}:3`); + if (process.platform === 'aix') { + // TODO: There is a known issue on AIX where the breakpoints aren't + // properly resolved yet when we reach this point. + // Eventually that should be figured out but for now we don't want + // to fail builds because of it. + t.match(cli.output, /#0 [^\n]+three-lines\.js\$?:2/); + t.match(cli.output, /#1 [^\n]+three-lines\.js\$?:3/); + } else { + t.match(cli.output, `#0 ${script}:2`); + t.match(cli.output, `#1 ${script}:3`); + } }) .then(() => cli.quit()) .then(null, onFatal); diff --git a/deps/node-inspect/test/cli/use-strict.test.js b/deps/node-inspect/test/cli/use-strict.test.js new file mode 100644 index 00000000000000..81f4d91a6a5802 --- /dev/null +++ b/deps/node-inspect/test/cli/use-strict.test.js @@ -0,0 +1,27 @@ +'use strict'; +const Path = require('path'); + +const { test } = require('tap'); + +const startCLI = require('./start-cli'); + +test('for whiles that starts with strict directive', (t) => { + const script = Path.join('examples', 'use-strict.js'); + const cli = startCLI([script]); + + function onFatal(error) { + cli.quit(); + throw error; + } + + return cli.waitFor(/break/) + .then(() => cli.waitForPrompt()) + .then(() => { + t.match( + cli.output, + /break in [^:]+:(?:1|2)[^\d]/, + 'pauses either on strict directive or first "real" line'); + }) + .then(() => cli.quit()) + .then(null, onFatal); +});