From c53b4ad03c33a36c2f4fb7363f3deeef8d060929 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 6 Dec 2020 12:04:41 +0100 Subject: [PATCH 01/24] lib: add primordials.SafeArrayIterator PR-URL: https://github.com/nodejs/node/pull/36532 Reviewed-By: Rich Trott --- lib/internal/modules/cjs/loader.js | 2 +- lib/internal/modules/esm/module_job.js | 9 +++++---- lib/internal/per_context/primordials.js | 7 +++++++ lib/internal/util/debuglog.js | 5 +++-- test/parallel/test-require-delete-array-iterator.js | 13 +++++++++++++ 5 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 test/parallel/test-require-delete-array-iterator.js diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 4ff756a0ab5c3f..7313c7ac847cd6 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -438,7 +438,7 @@ function trySelf(parentPath, request) { const EXPORTS_PATTERN = /^((?:@[^/\\%]+\/)?[^./\\%][^/\\%]*)(\/.*)?$/; function resolveExports(nmPath, request) { // The implementation's behavior is meant to mirror resolution in ESM. - const [, name, expansion = ''] = + const { 1: name, 2: expansion = '' } = StringPrototypeMatch(request, EXPORTS_PATTERN) || []; if (!name) return; diff --git a/lib/internal/modules/esm/module_job.js b/lib/internal/modules/esm/module_job.js index 9121cb388fccc2..0e1a7eb7b6a779 100644 --- a/lib/internal/modules/esm/module_job.js +++ b/lib/internal/modules/esm/module_job.js @@ -12,6 +12,7 @@ const { PromisePrototypeCatch, ReflectApply, RegExpPrototypeTest, + SafeArrayIterator, SafeSet, StringPrototypeIncludes, StringPrototypeMatch, @@ -76,9 +77,9 @@ class ModuleJob { }); if (promises !== undefined) - await PromiseAll(promises); + await PromiseAll(new SafeArrayIterator(promises)); - return PromiseAll(dependencyJobs); + return PromiseAll(new SafeArrayIterator(dependencyJobs)); }; // Promise for the list of all dependencyJobs. this.linked = link(); @@ -106,8 +107,8 @@ class ModuleJob { } jobsInGraph.add(moduleJob); const dependencyJobs = await moduleJob.linked; - return PromiseAll( - ArrayPrototypeMap(dependencyJobs, addJobsToDependencyGraph)); + return PromiseAll(new SafeArrayIterator( + ArrayPrototypeMap(dependencyJobs, addJobsToDependencyGraph))); }; await addJobsToDependencyGraph(this); diff --git a/lib/internal/per_context/primordials.js b/lib/internal/per_context/primordials.js index a4ea444ef7d832..135afd4d60ce56 100644 --- a/lib/internal/per_context/primordials.js +++ b/lib/internal/per_context/primordials.js @@ -263,6 +263,9 @@ primordials.SafeWeakSet = makeSafe( // Refs: https://tc39.es/ecma262/#sec-%typedarray%-intrinsic-object [ { name: 'TypedArray', original: Reflect.getPrototypeOf(Uint8Array) }, + { name: 'ArrayIterator', original: { + prototype: Reflect.getPrototypeOf(Array.prototype[Symbol.iterator]()), + } }, { name: 'StringIterator', original: { prototype: Reflect.getPrototypeOf(String.prototype[Symbol.iterator]()), } }, @@ -274,6 +277,10 @@ primordials.SafeWeakSet = makeSafe( copyPrototype(original.prototype, primordials, `${name}Prototype`); }); +primordials.SafeArrayIterator = createSafeIterator( + primordials.ArrayPrototypeSymbolIterator, + primordials.ArrayIteratorPrototypeNext +); primordials.SafeStringIterator = createSafeIterator( primordials.StringPrototypeSymbolIterator, primordials.StringIteratorPrototypeNext diff --git a/lib/internal/util/debuglog.js b/lib/internal/util/debuglog.js index a3b8a84772054e..46d3ed5613246e 100644 --- a/lib/internal/util/debuglog.js +++ b/lib/internal/util/debuglog.js @@ -6,6 +6,7 @@ const { ObjectDefineProperty, RegExp, RegExpPrototypeTest, + SafeArrayIterator, StringPrototypeToUpperCase } = primordials; @@ -78,7 +79,7 @@ function debuglog(set, cb) { debug = debuglogImpl(enabled, set); if (typeof cb === 'function') cb(debug); - debug(...args); + debug(...new SafeArrayIterator(args)); }; let enabled; let test = () => { @@ -86,7 +87,7 @@ function debuglog(set, cb) { test = () => enabled; return enabled; }; - const logger = (...args) => debug(...args); + const logger = (...args) => debug(...new SafeArrayIterator(args)); ObjectDefineProperty(logger, 'enabled', { get() { return test(); diff --git a/test/parallel/test-require-delete-array-iterator.js b/test/parallel/test-require-delete-array-iterator.js new file mode 100644 index 00000000000000..5424ef8b75da9d --- /dev/null +++ b/test/parallel/test-require-delete-array-iterator.js @@ -0,0 +1,13 @@ +'use strict'; + +const common = require('../common'); + + +const ArrayIteratorPrototype = + Object.getPrototypeOf(Array.prototype[Symbol.iterator]()); + +delete Array.prototype[Symbol.iterator]; +delete ArrayIteratorPrototype.next; + +require('../common/fixtures'); +import('../fixtures/es-modules/test-esm-ok.mjs').then(common.mustCall()); From 1355e52ff0a37cc12fba4e78c68d5cf61ef8ab31 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Tue, 20 Jul 2021 14:09:24 +0200 Subject: [PATCH 02/24] Revert "debugger: rename internal library for clarity" This reverts commit d0c7ab00f9fcbf6ba45c3f554fa75cf60ca1b2ce. --- lib/internal/{debugger => inspector}/_inspect.js | 4 ++-- lib/internal/{debugger => inspector}/inspect_client.js | 0 lib/internal/{debugger => inspector}/inspect_repl.js | 0 lib/internal/main/inspect.js | 2 +- node.gyp | 6 +++--- 5 files changed, 6 insertions(+), 6 deletions(-) rename lib/internal/{debugger => inspector}/_inspect.js (99%) rename lib/internal/{debugger => inspector}/inspect_client.js (100%) rename lib/internal/{debugger => inspector}/inspect_repl.js (100%) diff --git a/lib/internal/debugger/_inspect.js b/lib/internal/inspector/_inspect.js similarity index 99% rename from lib/internal/debugger/_inspect.js rename to lib/internal/inspector/_inspect.js index f0bd9331d086c7..43e62c874dc82c 100644 --- a/lib/internal/debugger/_inspect.js +++ b/lib/internal/inspector/_inspect.js @@ -31,8 +31,8 @@ const util = require('util'); const { 0: InspectClient, 1: createRepl } = [ - require('internal/debugger/inspect_client'), - require('internal/debugger/inspect_repl'), + require('internal/inspector/inspect_client'), + require('internal/inspector/inspect_repl'), ]; const debuglog = util.debuglog('inspect'); diff --git a/lib/internal/debugger/inspect_client.js b/lib/internal/inspector/inspect_client.js similarity index 100% rename from lib/internal/debugger/inspect_client.js rename to lib/internal/inspector/inspect_client.js diff --git a/lib/internal/debugger/inspect_repl.js b/lib/internal/inspector/inspect_repl.js similarity index 100% rename from lib/internal/debugger/inspect_repl.js rename to lib/internal/inspector/inspect_repl.js diff --git a/lib/internal/main/inspect.js b/lib/internal/main/inspect.js index 731ff1cd0dc7f0..10e7cbf2c2b48a 100644 --- a/lib/internal/main/inspect.js +++ b/lib/internal/main/inspect.js @@ -18,5 +18,5 @@ markBootstrapComplete(); // Start the debugger agent. process.nextTick(() => { - require('internal/debugger/_inspect').start(); + require('internal/inspector/_inspect').start(); }); diff --git a/node.gyp b/node.gyp index 8ba0dfebe890e8..ce902069ed6bac 100644 --- a/node.gyp +++ b/node.gyp @@ -125,9 +125,6 @@ 'lib/internal/crypto/sig.js', 'lib/internal/crypto/util.js', 'lib/internal/constants.js', - 'lib/internal/debugger/_inspect.js', - 'lib/internal/debugger/inspect_client.js', - 'lib/internal/debugger/inspect_repl.js', 'lib/internal/dgram.js', 'lib/internal/dns/promises.js', 'lib/internal/dns/utils.js', @@ -151,6 +148,9 @@ 'lib/internal/heap_utils.js', 'lib/internal/histogram.js', 'lib/internal/idna.js', + 'lib/internal/inspector/_inspect.js', + 'lib/internal/inspector/inspect_client.js', + 'lib/internal/inspector/inspect_repl.js', 'lib/internal/inspector_async_hook.js', 'lib/internal/js_stream_socket.js', 'lib/internal/linkedlist.js', From 7b5e17f7dc97510927b7dbbf4b0a7cde32e3611c Mon Sep 17 00:00:00 2001 From: Rafael Gonzaga Date: Mon, 27 Jul 2020 18:53:13 -0300 Subject: [PATCH 03/24] debugger: add usage example for `--port` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/38400 Reviewed-By: Michaël Zasso Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- lib/internal/inspector/_inspect.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/internal/inspector/_inspect.js b/lib/internal/inspector/_inspect.js index 43e62c874dc82c..487c8837752e8e 100644 --- a/lib/internal/inspector/_inspect.js +++ b/lib/internal/inspector/_inspect.js @@ -340,6 +340,7 @@ function startInspect(argv = process.argv.slice(2), console.error(`Usage: ${invokedAs} script.js`); console.error(` ${invokedAs} :`); + console.error(` ${invokedAs} --port=`); console.error(` ${invokedAs} -p `); process.exit(1); } From 8146a8ca50a6998dade4c9bd5cb8a472bae4fe79 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 25 Apr 2021 23:27:15 +0200 Subject: [PATCH 04/24] debugger: refactor `internal/inspector/_inspect` to use more primordials PR-URL: https://github.com/nodejs/node/pull/38406 Reviewed-By: Rich Trott --- lib/internal/inspector/_inspect.js | 287 +++++++++++++++-------------- 1 file changed, 153 insertions(+), 134 deletions(-) diff --git a/lib/internal/inspector/_inspect.js b/lib/internal/inspector/_inspect.js index 487c8837752e8e..668709eccce380 100644 --- a/lib/internal/inspector/_inspect.js +++ b/lib/internal/inspector/_inspect.js @@ -20,14 +20,52 @@ * IN THE SOFTWARE. */ -// TODO(trott): enable ESLint -/* eslint-disable */ +// TODO(aduh95): remove restricted syntax errors +/* eslint-disable no-restricted-syntax */ 'use strict'; + +const { + ArrayPrototypeConcat, + ArrayPrototypeForEach, + ArrayPrototypeJoin, + ArrayPrototypeMap, + ArrayPrototypePop, + ArrayPrototypeShift, + ArrayPrototypeSlice, + Error, + FunctionPrototypeBind, + Number, + Promise, + PromisePrototypeCatch, + PromisePrototypeThen, + PromiseResolve, + Proxy, + RegExpPrototypeSymbolMatch, + RegExpPrototypeSymbolSplit, + RegExpPrototypeTest, + StringPrototypeEndsWith, + StringPrototypeSplit, +} = primordials; + const { spawn } = require('child_process'); const { EventEmitter } = require('events'); const net = require('net'); const util = require('util'); +const { + AbortController, +} = require('internal/abort_controller'); + +const setTimeout = util.promisify(require('timers').setTimeout); +async function* setInterval(delay) { + while (true) { + await setTimeout(delay); + yield; + } +} + +// TODO(aduh95): remove console calls +const console = require('internal/console/global'); const { 0: InspectClient, 1: createRepl } = [ @@ -44,88 +82,72 @@ class StartupError extends Error { } } -function portIsFree(host, port, timeout = 9999) { - if (port === 0) return Promise.resolve(); // Binding to a random port. +async function portIsFree(host, port, timeout = 9999) { + if (port === 0) return; // Binding to a random port. const retryDelay = 150; - let didTimeOut = false; - - return new Promise((resolve, reject) => { - setTimeout(() => { - didTimeOut = true; - reject(new StartupError( - `Timeout (${timeout}) waiting for ${host}:${port} to be free`)); - }, timeout); + const ac = new AbortController(); + const { signal } = ac; - function pingPort() { - if (didTimeOut) return; + setTimeout(timeout).then(() => ac.abort()); + // eslint-disable-next-line no-unused-vars + for await (const _ of setInterval(retryDelay)) { + if (signal.aborted) { + throw new StartupError( + `Timeout (${timeout}) waiting for ${host}:${port} to be free`); + } + const error = await new Promise((resolve) => { 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(); - }); + socket.on('error', resolve); + socket.on('connect', resolve); + }); + if (error?.code === 'ECONNREFUSED') { + return; } - pingPort(); - }); + } } -function runScript(script, scriptArgs, inspectHost, inspectPort, childPrint) { - return portIsFree(inspectHost, inspectPort) - .then(() => { - return new Promise((resolve) => { - const needDebugBrk = process.version.match(/^v(6|7)\./); - const args = (needDebugBrk ? - ['--inspect', `--debug-brk=${inspectPort}`] : - [`--inspect-brk=${inspectPort}`]) - .concat([script], scriptArgs); - const child = spawn(process.execPath, args); - child.stdout.setEncoding('utf8'); - child.stderr.setEncoding('utf8'); - child.stdout.on('data', (chunk) => childPrint(chunk, 'stdout')); - child.stderr.on('data', (chunk) => childPrint(chunk, 'stderr')); - - let output = ''; - function waitForListenHint(text) { - output += text; - if (/Debugger listening on ws:\/\/\[?(.+?)\]?:(\d+)\//.test(output)) { - const host = RegExp.$1; - const port = Number.parseInt(RegExp.$2); - child.stderr.removeListener('data', waitForListenHint); - resolve([child, port, host]); - } - } - - child.stderr.on('data', waitForListenHint); - }); - }); +const debugRegex = /Debugger listening on ws:\/\/\[?(.+?)\]?:(\d+)\//; +async function runScript(script, scriptArgs, inspectHost, inspectPort, + childPrint) { + await portIsFree(inspectHost, inspectPort); + const args = ArrayPrototypeConcat( + [`--inspect-brk=${inspectPort}`, script], + scriptArgs); + const child = spawn(process.execPath, args); + child.stdout.setEncoding('utf8'); + child.stderr.setEncoding('utf8'); + child.stdout.on('data', (chunk) => childPrint(chunk, 'stdout')); + child.stderr.on('data', (chunk) => childPrint(chunk, 'stderr')); + + let output = ''; + return new Promise((resolve) => { + function waitForListenHint(text) { + output += text; + const debug = RegExpPrototypeSymbolMatch(debugRegex, output); + if (debug) { + const host = debug[1]; + const port = Number(debug[2]); + child.stderr.removeListener('data', waitForListenHint); + resolve([child, port, host]); + } + } + + child.stderr.on('data', waitForListenHint); + }); } function createAgentProxy(domain, client) { const agent = new EventEmitter(); - agent.then = (...args) => { + agent.then = (then, _catch) => { // TODO: potentially fetch the protocol and pretty-print it here. const descriptor = { [util.inspect.custom](depth, { stylize }) { return stylize(`[Agent ${domain}]`, 'special'); }, }; - return Promise.resolve(descriptor).then(...args); + return PromisePrototypeThen(PromiseResolve(descriptor), then, _catch); }; return new Proxy(agent, { @@ -148,25 +170,26 @@ class NodeInspector { this.child = null; if (options.script) { - this._runScript = runScript.bind(null, - options.script, - options.scriptArgs, - options.host, - options.port, - this.childPrint.bind(this)); + this._runScript = FunctionPrototypeBind( + runScript, null, + options.script, + options.scriptArgs, + options.host, + options.port, + FunctionPrototypeBind(this.childPrint, this)); } else { this._runScript = - () => Promise.resolve([null, options.port, options.host]); + () => PromiseResolve([null, options.port, options.host]); } this.client = new InspectClient(); this.domainNames = ['Debugger', 'HeapProfiler', 'Profiler', 'Runtime']; - this.domainNames.forEach((domain) => { + ArrayPrototypeForEach(this.domainNames, (domain) => { this[domain] = createAgentProxy(domain, this.client); }); this.handleDebugEvent = (fullName, params) => { - const { 0: domain, 1: name } = fullName.split('.'); + const { 0: domain, 1: name } = StringPrototypeSplit(fullName, '.'); if (domain in this) { this[domain].emit(name, params); } @@ -176,19 +199,16 @@ class NodeInspector { // Handle all possible exits process.on('exit', () => this.killChild()); - process.once('SIGTERM', process.exit.bind(process, 0)); - process.once('SIGHUP', process.exit.bind(process, 0)); - - this.run() - .then(() => startRepl()) - .then((repl) => { - this.repl = repl; - this.repl.on('exit', () => { - process.exit(0); - }); - this.paused = false; - }) - .then(null, (error) => process.nextTick(() => { throw error; })); + const exitCodeZero = () => process.exit(0); + process.once('SIGTERM', exitCodeZero); + process.once('SIGHUP', exitCodeZero); + + PromisePrototypeCatch(PromisePrototypeThen(this.run(), () => { + const repl = startRepl(); + this.repl = repl; + this.repl.on('exit', exitCodeZero); + this.paused = false; + }), (error) => process.nextTick(() => { throw error; })); } suspendReplWhile(fn) { @@ -197,16 +217,16 @@ class NodeInspector { } this.stdin.pause(); this.paused = true; - return new Promise((resolve) => { + return PromisePrototypeCatch(PromisePrototypeThen(new Promise((resolve) => { resolve(fn()); - }).then(() => { + }), () => { this.paused = false; if (this.repl) { this.repl.resume(); this.repl.displayPrompt(); } this.stdin.resume(); - }).then(null, (error) => process.nextTick(() => { throw error; })); + }), (error) => process.nextTick(() => { throw error; })); } killChild() { @@ -217,37 +237,28 @@ class NodeInspector { } } - run() { + async run() { this.killChild(); - return this._runScript().then(({ 0: child, 1: port, 2: host }) => { - this.child = child; - - let connectionAttempts = 0; - const attemptConnect = () => { - ++connectionAttempts; - debuglog('connection attempt #%d', connectionAttempts); - this.stdout.write('.'); - return this.client.connect(port, host) - .then(() => { - debuglog('connection established'); - this.stdout.write(' ok\n'); - }, (error) => { - debuglog('connect failed', error); - // If it's failed to connect 5 times then print failed message - if (connectionAttempts >= 5) { - this.stdout.write(' failed to connect, please retry\n'); - process.exit(1); - } - - return new Promise((resolve) => setTimeout(resolve, 1000)) - .then(attemptConnect); - }); - }; - - this.print(`connecting to ${host}:${port} ..`, false); - return attemptConnect(); - }); + const { 0: child, 1: port, 2: host } = await this._runScript(); + this.child = child; + + this.print(`connecting to ${host}:${port} ..`, false); + for (let attempt = 0; attempt < 5; attempt++) { + debuglog('connection attempt #%d', attempt); + this.stdout.write('.'); + try { + await this.client.connect(port, host); + debuglog('connection established'); + this.stdout.write(' ok\n'); + return; + } catch (error) { + debuglog('connect failed', error); + await setTimeout(1000); + } + } + this.stdout.write(' failed to connect, please retry\n'); + process.exit(1); } clearLine() { @@ -266,16 +277,19 @@ class NodeInspector { #stdioBuffers = { stdout: '', stderr: '' }; childPrint(text, which) { - const lines = (this.#stdioBuffers[which] + text) - .split(/\r\n|\r|\n/g); + const lines = RegExpPrototypeSymbolSplit( + /\r\n|\r|\n/g, + this.#stdioBuffers[which] + text); this.#stdioBuffers[which] = ''; if (lines[lines.length - 1] !== '') { - this.#stdioBuffers[which] = lines.pop(); + this.#stdioBuffers[which] = ArrayPrototypePop(lines); } - const textToPrint = lines.map((chunk) => `< ${chunk}`).join('\n'); + const textToPrint = ArrayPrototypeJoin( + ArrayPrototypeMap(lines, (chunk) => `< ${chunk}`), + '\n'); if (lines.length) { this.print(textToPrint, true); @@ -284,36 +298,41 @@ class NodeInspector { } } - if (textToPrint.endsWith('Waiting for the debugger to disconnect...\n')) { + if (StringPrototypeEndsWith( + textToPrint, + 'Waiting for the debugger to disconnect...\n' + )) { this.killChild(); } } } -function parseArgv([target, ...args]) { +function parseArgv(args) { + const target = ArrayPrototypeShift(args); let host = '127.0.0.1'; let port = 9229; let isRemote = false; let script = target; let scriptArgs = args; - const hostMatch = target.match(/^([^:]+):(\d+)$/); - const portMatch = target.match(/^--port=(\d+)$/); + const hostMatch = RegExpPrototypeSymbolMatch(/^([^:]+):(\d+)$/, target); + const portMatch = RegExpPrototypeSymbolMatch(/^--port=(\d+)$/, target); if (hostMatch) { // Connecting to remote debugger host = hostMatch[1]; - port = parseInt(hostMatch[2], 10); + port = Number(hostMatch[2]); isRemote = true; script = null; } else if (portMatch) { // Start on custom port - port = parseInt(portMatch[1], 10); + port = Number(portMatch[1]); script = args[0]; - scriptArgs = args.slice(1); - } else if (args.length === 1 && /^\d+$/.test(args[0]) && target === '-p') { + scriptArgs = ArrayPrototypeSlice(args, 1); + } else if (args.length === 1 && RegExpPrototypeTest(/^\d+$/, args[0]) && + target === '-p') { // Start debugger against a given pid - const pid = parseInt(args[0], 10); + const pid = Number(args[0]); try { process._debugProcess(pid); } catch (e) { @@ -332,7 +351,7 @@ function parseArgv([target, ...args]) { }; } -function startInspect(argv = process.argv.slice(2), +function startInspect(argv = ArrayPrototypeSlice(process.argv, 2), stdin = process.stdin, stdout = process.stdout) { if (argv.length < 1) { From cc589f33727f17df0f390c59ad04e93fb0455bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Wed, 26 May 2021 09:00:14 +0200 Subject: [PATCH 05/24] debugger: wait for V8 debugger to be enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs: https://github.com/nodejs/node/pull/38273#issuecomment-848438189 PR-URL: https://github.com/nodejs/node/pull/38811 Reviewed-By: Antoine du Hamel Reviewed-By: Richard Lau Reviewed-By: Beth Griggs Reviewed-By: Gerhard Stöbich Reviewed-By: Rich Trott --- lib/internal/inspector/_inspect.js | 4 ++-- lib/internal/inspector/inspect_repl.js | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/internal/inspector/_inspect.js b/lib/internal/inspector/_inspect.js index 668709eccce380..528416c75aaee1 100644 --- a/lib/internal/inspector/_inspect.js +++ b/lib/internal/inspector/_inspect.js @@ -203,8 +203,8 @@ class NodeInspector { process.once('SIGTERM', exitCodeZero); process.once('SIGHUP', exitCodeZero); - PromisePrototypeCatch(PromisePrototypeThen(this.run(), () => { - const repl = startRepl(); + PromisePrototypeCatch(PromisePrototypeThen(this.run(), async () => { + const repl = await startRepl(); this.repl = repl; this.repl.on('exit', exitCodeZero); this.paused = false; diff --git a/lib/internal/inspector/inspect_repl.js b/lib/internal/inspector/inspect_repl.js index 128ae697105a3d..cad22aed83cc2b 100644 --- a/lib/internal/inspector/inspect_repl.js +++ b/lib/internal/inspector/inspect_repl.js @@ -1077,7 +1077,7 @@ function createRepl(inspector) { .then(() => Runtime.runIfWaitingForDebugger()); } - return function startRepl() { + return async function startRepl() { inspector.client.on('close', () => { resetOnStart(); }); @@ -1085,6 +1085,9 @@ function createRepl(inspector) { initAfterStart(); }); + // Init once for the initial connection + await initAfterStart(); + const replOptions = { prompt: 'debug> ', input: inspector.stdin, @@ -1103,9 +1106,6 @@ function createRepl(inspector) { repl.emit('SIGINT'); }); - // Init once for the initial connection - initAfterStart(); - return repl; }; } From e036082e568aa417f67f50d3d4da06918747bb95 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 29 May 2021 13:58:32 -0700 Subject: [PATCH 06/24] debugger: revise async iterator usage to comply with lint rules I'm not sure that this is any clearer than the existing code, but I don't think it's significantly less clear, and it avoids comment disabling a lint rule. PR-URL: https://github.com/nodejs/node/pull/38847 Reviewed-By: Antoine du Hamel Reviewed-By: James M Snell --- lib/internal/inspector/_inspect.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/internal/inspector/_inspect.js b/lib/internal/inspector/_inspect.js index 528416c75aaee1..924b5a7f8a9bb9 100644 --- a/lib/internal/inspector/_inspect.js +++ b/lib/internal/inspector/_inspect.js @@ -91,8 +91,9 @@ async function portIsFree(host, port, timeout = 9999) { setTimeout(timeout).then(() => ac.abort()); - // eslint-disable-next-line no-unused-vars - for await (const _ of setInterval(retryDelay)) { + const asyncIterator = setInterval(retryDelay); + while (true) { + await asyncIterator.next(); if (signal.aborted) { throw new StartupError( `Timeout (${timeout}) waiting for ${host}:${port} to be free`); From e62210503302709758b5d4a8be6ae194f372abd3 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 5 Jun 2021 18:57:30 -0700 Subject: [PATCH 07/24] debugger: reduce scope of eslint disable comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current code masks setInterval and setTimeout with promisified versions. This can be confusing to read and causes lint errors. Replace masking with use of pSetInterval and pSetTimeout instead. Move disabling of lint rule from entire file to the one remaining line (after the above changes) that still needs it. PR-URL: https://github.com/nodejs/node/pull/38946 Reviewed-By: Antoine du Hamel Reviewed-By: Michaël Zasso Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Luigi Pinca --- lib/internal/inspector/_inspect.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/internal/inspector/_inspect.js b/lib/internal/inspector/_inspect.js index 924b5a7f8a9bb9..65482e791d0b4c 100644 --- a/lib/internal/inspector/_inspect.js +++ b/lib/internal/inspector/_inspect.js @@ -20,9 +20,6 @@ * IN THE SOFTWARE. */ -// TODO(aduh95): remove restricted syntax errors -/* eslint-disable no-restricted-syntax */ - 'use strict'; const { @@ -56,10 +53,10 @@ const { AbortController, } = require('internal/abort_controller'); -const setTimeout = util.promisify(require('timers').setTimeout); -async function* setInterval(delay) { +const pSetTimeout = util.promisify(require('timers').setTimeout); +async function* pSetInterval(delay) { while (true) { - await setTimeout(delay); + await pSetTimeout(delay); yield; } } @@ -89,13 +86,13 @@ async function portIsFree(host, port, timeout = 9999) { const ac = new AbortController(); const { signal } = ac; - setTimeout(timeout).then(() => ac.abort()); + pSetTimeout(timeout).then(() => ac.abort()); - const asyncIterator = setInterval(retryDelay); + const asyncIterator = pSetInterval(retryDelay); while (true) { await asyncIterator.next(); if (signal.aborted) { - throw new StartupError( + throw new StartupError( // eslint-disable-line no-restricted-syntax `Timeout (${timeout}) waiting for ${host}:${port} to be free`); } const error = await new Promise((resolve) => { @@ -255,7 +252,7 @@ class NodeInspector { return; } catch (error) { debuglog('connect failed', error); - await setTimeout(1000); + await pSetTimeout(1000); } } this.stdout.write(' failed to connect, please retry\n'); From 9b960d910c663f465c021b83b3f014d2f51b0f80 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 26 Apr 2021 10:10:54 +0200 Subject: [PATCH 08/24] debugger: enable linter on `internal/inspector/inspect_client` PR-URL: https://github.com/nodejs/node/pull/38417 Reviewed-By: James M Snell Reviewed-By: Rich Trott --- lib/internal/inspector/inspect_client.js | 52 +++++++++++++----------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/lib/internal/inspector/inspect_client.js b/lib/internal/inspector/inspect_client.js index 831a7fda1cdff1..ba1e9bc30ce5ce 100644 --- a/lib/internal/inspector/inspect_client.js +++ b/lib/internal/inspector/inspect_client.js @@ -20,17 +20,28 @@ * IN THE SOFTWARE. */ -// TODO(trott): enable ESLint -/* eslint-disable */ +// TODO(aduh95): use errors exported by the internal/errors module +/* eslint-disable no-restricted-syntax */ 'use strict'; + +const { + ArrayPrototypePush, + Error, + ErrorCaptureStackTrace, + FunctionPrototypeBind, + JSONParse, + JSONStringify, + ObjectKeys, + Promise, +} = primordials; + const Buffer = require('buffer').Buffer; const { EventEmitter } = require('events'); const http = require('http'); const URL = require('url'); -const util = require('util'); -const debuglog = util.debuglog('inspect'); +const debuglog = require('internal/util/debuglog').debuglog('inspect'); const kOpCodeText = 0x1; const kOpCodeClose = 0x8; @@ -49,14 +60,10 @@ const kTwoBytePayloadLengthField = 126; const kEightBytePayloadLengthField = 127; const kMaskingKeyWidthInBytes = 4; -function isEmpty(obj) { - return Object.keys(obj).length === 0; -} - function unpackError({ code, message, data }) { const err = new Error(`${message} - ${data}`); err.code = code; - Error.captureStackTrace(err, unpackError); + ErrorCaptureStackTrace(err, unpackError); return err; } @@ -169,7 +176,7 @@ function decodeFrameHybi17(data) { class Client extends EventEmitter { constructor() { super(); - this.handleChunk = this._handleChunk.bind(this); + this.handleChunk = FunctionPrototypeBind(this._handleChunk, this); this._port = undefined; this._host = undefined; @@ -202,7 +209,7 @@ class Client extends EventEmitter { } let payload; try { - payload = JSON.parse(payloadStr); + payload = JSONParse(payloadStr); } catch (parseError) { parseError.string = payloadStr; throw parseError; @@ -247,9 +254,9 @@ class Client extends EventEmitter { const data = { id: ++this._lastId, method, params }; this._pending[data.id] = (error, result) => { if (error) reject(unpackError(error)); - else resolve(isEmpty(result) ? undefined : result); + else resolve(ObjectKeys(result).length ? result : undefined); }; - const json = JSON.stringify(data); + const json = JSONStringify(data); debuglog('> %s', json); this._socket.write(encodeFrameHybi17(Buffer.from(json))); }); @@ -273,15 +280,15 @@ class Client extends EventEmitter { return; } try { - resolve(JSON.parse(resBody)); - } catch (parseError) { + resolve(JSONParse(resBody)); + } catch { reject(new Error(`Response didn't contain JSON: ${resBody}`)); } } httpRes.on('error', reject); - httpRes.on('data', (chunk) => chunks.push(chunk)); + httpRes.on('data', (chunk) => ArrayPrototypePush(chunks, chunk)); httpRes.on('end', parseChunks); } @@ -290,17 +297,16 @@ class Client extends EventEmitter { }); } - connect(port, host) { + async connect(port, host) { this._port = port; this._host = host; - return this._discoverWebsocketPath() - .then((urlPath) => this._connectWebsocket(urlPath)); + const urlPath = await this._discoverWebsocketPath(); + return this._connectWebsocket(urlPath); } - _discoverWebsocketPath() { - return this._fetchJSON('/json') - .then(({ 0: { webSocketDebuggerUrl } }) => - URL.parse(webSocketDebuggerUrl).path); + async _discoverWebsocketPath() { + const { 0: { webSocketDebuggerUrl } } = await this._fetchJSON('/json'); + return URL.parse(webSocketDebuggerUrl).path; } _connectWebsocket(urlPath) { From 5ae4a50018ec10bc3b1e28397bb4f80ca7128cdd Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 6 Jun 2021 10:23:48 -0700 Subject: [PATCH 09/24] debugger: remove unnecessary boilerplate copyright comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/38952 Reviewed-By: Michaël Zasso Reviewed-By: Antoine du Hamel Reviewed-By: Colin Ihrig Reviewed-By: Darshan Sen Reviewed-By: James M Snell Reviewed-By: Luigi Pinca --- lib/internal/inspector/_inspect.js | 22 ---------------------- lib/internal/inspector/inspect_client.js | 22 ---------------------- lib/internal/inspector/inspect_repl.js | 22 ---------------------- 3 files changed, 66 deletions(-) diff --git a/lib/internal/inspector/_inspect.js b/lib/internal/inspector/_inspect.js index 65482e791d0b4c..4786a478fe14d8 100644 --- a/lib/internal/inspector/_inspect.js +++ b/lib/internal/inspector/_inspect.js @@ -1,25 +1,3 @@ -/* - * Copyright Node.js contributors. All rights reserved. - * - * 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. - */ - 'use strict'; const { diff --git a/lib/internal/inspector/inspect_client.js b/lib/internal/inspector/inspect_client.js index ba1e9bc30ce5ce..4c89c56af93ef6 100644 --- a/lib/internal/inspector/inspect_client.js +++ b/lib/internal/inspector/inspect_client.js @@ -1,25 +1,3 @@ -/* - * Copyright Node.js contributors. All rights reserved. - * - * 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. - */ - // TODO(aduh95): use errors exported by the internal/errors module /* eslint-disable no-restricted-syntax */ diff --git a/lib/internal/inspector/inspect_repl.js b/lib/internal/inspector/inspect_repl.js index cad22aed83cc2b..a9daa88c30d435 100644 --- a/lib/internal/inspector/inspect_repl.js +++ b/lib/internal/inspector/inspect_repl.js @@ -1,25 +1,3 @@ -/* - * Copyright Node.js contributors. All rights reserved. - * - * 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. - */ - // TODO(trott): enable ESLint /* eslint-disable */ From ccc69e0d16036343147ca2a0d3f74cc92b89fc71 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 19 Sep 2020 09:01:00 -0700 Subject: [PATCH 10/24] debugger: align message with Node.js standard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Node.js uses (or will use) _Ctrl+C_ with no spaces. To unify the messages from inspect with other messages from the REPL and elsewhere, make that change in node-inspect too. PR-URL: https://github.com/nodejs/node/pull/38400 Reviewed-By: Michaël Zasso Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- lib/internal/inspector/inspect_repl.js | 4 ++-- test/sequential/test-debugger-exec.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/internal/inspector/inspect_repl.js b/lib/internal/inspector/inspect_repl.js index a9daa88c30d435..5e10dad2e147fd 100644 --- a/lib/internal/inspector/inspect_repl.js +++ b/lib/internal/inspector/inspect_repl.js @@ -1008,7 +1008,7 @@ function createRepl(inspector) { repl.setPrompt('> '); - print('Press Ctrl + C to leave debug repl'); + print('Press Ctrl+C to leave debug repl'); repl.displayPrompt(); }, @@ -1080,7 +1080,7 @@ function createRepl(inspector) { repl.on('reset', initializeContext); repl.defineCommand('interrupt', () => { - // We want this for testing purposes where sending CTRL-C can be tricky. + // We want this for testing purposes where sending Ctrl+C can be tricky. repl.emit('SIGINT'); }); diff --git a/test/sequential/test-debugger-exec.js b/test/sequential/test-debugger-exec.js index 15e7e212cf2466..f47eaaa5a6f62d 100644 --- a/test/sequential/test-debugger-exec.js +++ b/test/sequential/test-debugger-exec.js @@ -31,7 +31,7 @@ const assert = require('assert'); .then(() => { assert.match( cli.output, - /Press Ctrl \+ C to leave debug repl\n+> /, + /Press Ctrl\+C to leave debug repl\n+> /, 'shows hint for how to leave repl'); assert.doesNotMatch(cli.output, /debug>/, 'changes the repl style'); }) From 8b16b8277a1e71fc36e45dfa57cf8faf3a713040 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Mon, 3 May 2021 20:29:07 -0700 Subject: [PATCH 11/24] debugger: wrap lines longer than 80 chars Wrap lines more than 80 chararcters long in inspect_repl.js so we can disable specific rules. PR-URL: https://github.com/nodejs/node/pull/38529 Reviewed-By: Antoine du Hamel Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- lib/internal/inspector/inspect_repl.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/internal/inspector/inspect_repl.js b/lib/internal/inspector/inspect_repl.js index 5e10dad2e147fd..68217267276fd4 100644 --- a/lib/internal/inspector/inspect_repl.js +++ b/lib/internal/inspector/inspect_repl.js @@ -1050,7 +1050,8 @@ function createRepl(inspector) { .then(() => Debugger.setPauseOnExceptions({ state: 'none' })) .then(() => Debugger.setAsyncCallStackDepth({ maxDepth: 0 })) .then(() => Debugger.setBlackboxPatterns({ patterns: [] })) - .then(() => Debugger.setPauseOnExceptions({ state: pauseOnExceptionState })) + .then(() => + Debugger.setPauseOnExceptions({ state: pauseOnExceptionState })) .then(() => restoreBreakpoints()) .then(() => Runtime.runIfWaitingForDebugger()); } From 62131f69f3b4733ef26d4b8d1ae8a0141a8b2eee Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Mon, 3 May 2021 20:45:03 -0700 Subject: [PATCH 12/24] debugger: avoid non-ASCII char in code file Avoid non-ASCII char in lib code as a single non-ASCII char forces all the chars to be stored inefficiently, bloating the binary size. This also brings the file closer to compatibility with our lint rules. PR-URL: https://github.com/nodejs/node/pull/38529 Reviewed-By: Antoine du Hamel Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- lib/internal/inspector/inspect_repl.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/internal/inspector/inspect_repl.js b/lib/internal/inspector/inspect_repl.js index 68217267276fd4..335234080a8b94 100644 --- a/lib/internal/inspector/inspect_repl.js +++ b/lib/internal/inspector/inspect_repl.js @@ -353,7 +353,10 @@ function createRepl(inspector) { [util.inspect.custom](depth, { stylize }) { const { startTime, endTime } = this.data; - return stylize(`[Profile ${endTime - startTime}μs]`, 'special'); + return stylize( + `[Profile ${endTime - startTime}${String.fromCharCode(956)}s]`, + 'special' + ); } save(filename = 'node.cpuprofile') { From d025841ecaba66208dfe3c35b60d6e296d0542e0 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Mon, 3 May 2021 20:46:14 -0700 Subject: [PATCH 13/24] debugger: disable only the lint rules required by current file state PR-URL: https://github.com/nodejs/node/pull/38529 Reviewed-By: Antoine du Hamel Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- lib/internal/inspector/inspect_repl.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/internal/inspector/inspect_repl.js b/lib/internal/inspector/inspect_repl.js index 335234080a8b94..1b829c99061f45 100644 --- a/lib/internal/inspector/inspect_repl.js +++ b/lib/internal/inspector/inspect_repl.js @@ -1,5 +1,6 @@ // TODO(trott): enable ESLint -/* eslint-disable */ +/* eslint-disable getter-return, no-restricted-syntax, + node-core/prefer-primordials */ 'use strict'; const FS = require('fs'); @@ -353,10 +354,8 @@ function createRepl(inspector) { [util.inspect.custom](depth, { stylize }) { const { startTime, endTime } = this.data; - return stylize( - `[Profile ${endTime - startTime}${String.fromCharCode(956)}s]`, - 'special' - ); + const MU = String.fromChar(956); + return stylize(`[Profile ${endTime - startTime}${MU}s]`, 'special'); } save(filename = 'node.cpuprofile') { From e86361af3d4d415f389e7e037a5616a1cb1790f2 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Wed, 5 May 2021 11:21:27 +0200 Subject: [PATCH 14/24] debugger: refactor to use internal modules This avoids loading the entirety of `node:util` and `node:url` and their dependencies while only a subset is actually used by this module. PR-URL: https://github.com/nodejs/node/pull/38550 Reviewed-By: James M Snell Reviewed-By: Darshan Sen --- lib/internal/inspector/inspect_repl.js | 33 +++++++++++++------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/internal/inspector/inspect_repl.js b/lib/internal/inspector/inspect_repl.js index 1b829c99061f45..4bb7cd05bd1a30 100644 --- a/lib/internal/inspector/inspect_repl.js +++ b/lib/internal/inspector/inspect_repl.js @@ -6,11 +6,12 @@ const FS = require('fs'); const Path = require('path'); const Repl = require('repl'); -const util = require('util'); const vm = require('vm'); -const fileURLToPath = require('url').fileURLToPath; +const { fileURLToPath } = require('internal/url'); -const debuglog = util.debuglog('inspect'); +const { customInspectSymbol } = require('internal/util'); +const { inspect: utilInspect } = require('internal/util/inspect'); +const debuglog = require('internal/util/debuglog').debuglog('inspect'); const SHORTCUTS = { cont: 'c', @@ -148,12 +149,12 @@ class RemoteObject { } } - [util.inspect.custom](depth, opts) { + [customInspectSymbol](depth, opts) { function formatProperty(prop) { switch (prop.type) { case 'string': case 'undefined': - return util.inspect(prop.value, opts); + return utilInspect(prop.value, opts); case 'number': case 'boolean': @@ -162,7 +163,7 @@ class RemoteObject { case 'object': case 'symbol': if (prop.subtype === 'date') { - return util.inspect(new Date(prop.value), opts); + return utilInspect(new Date(prop.value), opts); } if (prop.subtype === 'array') { return opts.stylize(prop.value, 'special'); @@ -178,7 +179,7 @@ class RemoteObject { case 'number': case 'string': case 'undefined': - return util.inspect(this.value, opts); + return utilInspect(this.value, opts); case 'symbol': return opts.stylize(this.description, 'special'); @@ -192,10 +193,10 @@ class RemoteObject { case 'object': switch (this.subtype) { case 'date': - return util.inspect(new Date(this.description), opts); + return utilInspect(new Date(this.description), opts); case 'null': - return util.inspect(null, opts); + return utilInspect(null, opts); case 'regexp': return opts.stylize(this.description, 'regexp'); @@ -243,11 +244,11 @@ class ScopeSnapshot { this.completionGroup = properties.map((prop) => prop.name); } - [util.inspect.custom](depth, opts) { + [customInspectSymbol](depth, opts) { const type = `${this.type[0].toUpperCase()}${this.type.slice(1)}`; const name = this.name ? `<${this.name}>` : ''; const prefix = `${type}${name} `; - return util.inspect(this.properties, opts) + return utilInspect(this.properties, opts) .replace(/^Map /, prefix); } } @@ -296,7 +297,7 @@ function createRepl(inspector) { const INSPECT_OPTIONS = { colors: inspector.stdout.isTTY }; function inspect(value) { - return util.inspect(value, INSPECT_OPTIONS); + return utilInspect(value, INSPECT_OPTIONS); } function print(value, addNewline = true) { @@ -336,7 +337,7 @@ function createRepl(inspector) { function listScripts(displayNatives = false) { print(formatScripts(displayNatives)); } - listScripts[util.inspect.custom] = function listWithoutInternal() { + listScripts[customInspectSymbol] = function listWithoutInternal() { return formatScripts(); }; @@ -352,7 +353,7 @@ function createRepl(inspector) { return p; } - [util.inspect.custom](depth, { stylize }) { + [customInspectSymbol](depth, { stylize }) { const { startTime, endTime } = this.data; const MU = String.fromChar(956); return stylize(`[Profile ${endTime - startTime}${MU}s]`, 'special'); @@ -373,7 +374,7 @@ function createRepl(inspector) { this.delta = delta; } - [util.inspect.custom](depth, options) { + [customInspectSymbol](depth, options) { const { scriptId, lineNumber, columnNumber, delta, scriptSource } = this; const start = Math.max(1, lineNumber - delta + 1); const end = lineNumber + delta + 1; @@ -439,7 +440,7 @@ function createRepl(inspector) { } class Backtrace extends Array { - [util.inspect.custom]() { + [customInspectSymbol]() { return this.map((callFrame, idx) => { const { location: { scriptId, lineNumber, columnNumber }, From 22320ed67ca2771bc45050a85c6aee2be266531c Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Tue, 27 Apr 2021 12:27:39 +0200 Subject: [PATCH 15/24] debugger: refactor `inspect_repl` to use primordials PR-URL: https://github.com/nodejs/node/pull/38551 Reviewed-By: Rich Trott Reviewed-By: James M Snell --- lib/internal/inspector/inspect_repl.js | 567 ++++++++++++++----------- 1 file changed, 316 insertions(+), 251 deletions(-) diff --git a/lib/internal/inspector/inspect_repl.js b/lib/internal/inspector/inspect_repl.js index 4bb7cd05bd1a30..67b7f73aa1b25e 100644 --- a/lib/internal/inspector/inspect_repl.js +++ b/lib/internal/inspector/inspect_repl.js @@ -1,8 +1,55 @@ // TODO(trott): enable ESLint -/* eslint-disable getter-return, no-restricted-syntax, - node-core/prefer-primordials */ +/* eslint-disable getter-return, no-restricted-syntax */ 'use strict'; + +const { + Array, + ArrayFrom, + ArrayPrototypeFilter, + ArrayPrototypeFind, + ArrayPrototypeForEach, + ArrayPrototypeIncludes, + ArrayPrototypeIndexOf, + ArrayPrototypeJoin, + ArrayPrototypeMap, + ArrayPrototypePush, + ArrayPrototypeSlice, + ArrayPrototypeSome, + ArrayPrototypeSplice, + Date, + Error, + FunctionPrototypeCall, + JSONStringify, + MathMax, + ObjectAssign, + ObjectDefineProperty, + ObjectKeys, + ObjectValues, + Promise, + PromiseAll, + PromisePrototypeCatch, + PromisePrototypeThen, + PromiseResolve, + ReflectGetOwnPropertyDescriptor, + ReflectOwnKeys, + RegExpPrototypeSymbolMatch, + RegExpPrototypeSymbolReplace, + SafeArrayIterator, + SafeMap, + String, + StringFromCharCode, + StringPrototypeEndsWith, + StringPrototypeIncludes, + StringPrototypeRepeat, + StringPrototypeSlice, + StringPrototypeSplit, + StringPrototypeStartsWith, + StringPrototypeToUpperCase, + StringPrototypeTrim, + TypeError, +} = primordials; + const FS = require('fs'); const Path = require('path'); const Repl = require('repl'); @@ -24,7 +71,7 @@ const SHORTCUTS = { run: 'r', }; -const HELP = ` +const HELP = StringPrototypeTrim(` run, restart, r Run the application or reconnect kill Kill a running application or disconnect @@ -61,88 +108,83 @@ profiles[n].save(filepath = 'node.cpuprofile') takeHeapSnapshot(filepath = 'node.heapsnapshot') Take a heap snapshot and save to disk as JSON. -`.trim(); +`); const FUNCTION_NAME_PATTERN = /^(?:function\*? )?([^(\s]+)\(/; function extractFunctionName(description) { - const fnNameMatch = description.match(FUNCTION_NAME_PATTERN); + const fnNameMatch = + RegExpPrototypeSymbolMatch(FUNCTION_NAME_PATTERN, description); return fnNameMatch ? `: ${fnNameMatch[1]}` : ''; } -const PUBLIC_BUILTINS = require('module').builtinModules; -const NATIVES = PUBLIC_BUILTINS ? internalBinding('natives') : {}; +const { + moduleIds: PUBLIC_BUILTINS, +} = internalBinding('native_module'); +const NATIVES = internalBinding('natives'); function isNativeUrl(url) { - url = url.replace(/\.js$/, ''); - if (PUBLIC_BUILTINS) { - if (url.startsWith('node:internal/') || PUBLIC_BUILTINS.includes(url)) - return true; - } + url = RegExpPrototypeSymbolReplace(/\.js$/, url, ''); - return url in NATIVES || url === 'bootstrap_node'; + return StringPrototypeStartsWith(url, 'node:internal/') || + ArrayPrototypeIncludes(PUBLIC_BUILTINS, url) || + url in NATIVES || url === 'bootstrap_node'; } function getRelativePath(filenameOrURL) { - const dir = Path.join(Path.resolve(), 'x').slice(0, -1); + const dir = StringPrototypeSlice(Path.join(Path.resolve(), 'x'), 0, -1); - const filename = filenameOrURL.startsWith('file://') ? + const filename = StringPrototypeStartsWith(filenameOrURL, 'file://') ? fileURLToPath(filenameOrURL) : filenameOrURL; // Change path to relative, if possible - if (filename.indexOf(dir) === 0) { - return filename.slice(dir.length); + if (StringPrototypeStartsWith(filename, dir)) { + return StringPrototypeSlice(filename, dir.length); } return filename; } -function toCallback(promise, callback) { - function forward(...args) { - process.nextTick(() => callback(...args)); - } - promise.then(forward.bind(null, null), forward); -} - // Adds spaces and prefix to number // maxN is a maximum number we should have space for function leftPad(n, prefix, maxN) { const s = n.toString(); - const nchars = Math.max(2, String(maxN).length) + 1; - const nspaces = nchars - s.length - 1; + const nchars = MathMax(2, String(maxN).length); + const nspaces = nchars - s.length; - return prefix + ' '.repeat(nspaces) + s; + return prefix + StringPrototypeRepeat(' ', nspaces) + s; } function markSourceColumn(sourceText, position, useColors) { if (!sourceText) return ''; - const head = sourceText.slice(0, position); - let tail = sourceText.slice(position); + const head = StringPrototypeSlice(sourceText, 0, position); + let tail = StringPrototypeSlice(sourceText, position); // Colourize char if stdout supports colours if (useColors) { - tail = tail.replace(/(.+?)([^\w]|$)/, '\u001b[32m$1\u001b[39m$2'); + tail = RegExpPrototypeSymbolReplace(/(.+?)([^\w]|$)/, tail, + '\u001b[32m$1\u001b[39m$2'); } // Return source line with coloured char at `position` - return [head, tail].join(''); + return head + tail; } function extractErrorMessage(stack) { if (!stack) return ''; - const m = stack.match(/^\w+: ([^\n]+)/); - return m ? m[1] : stack; + const m = RegExpPrototypeSymbolMatch(/^\w+: ([^\n]+)/, stack); + return m?.[1] ?? stack; } function convertResultToError(result) { const { className, description } = result; const err = new Error(extractErrorMessage(description)); err.stack = description; - Object.defineProperty(err, 'name', { value: className }); + ObjectDefineProperty(err, 'name', { value: className }); return err; } class RemoteObject { constructor(attributes) { - Object.assign(this, attributes); + ObjectAssign(this, attributes); if (this.type === 'number') { this.value = this.unserializableValue ? +this.unserializableValue : +this.value; @@ -205,18 +247,21 @@ class RemoteObject { break; } if (this.preview) { - const props = this.preview.properties - .map((prop, idx) => { + const props = ArrayPrototypeMap( + this.preview.properties, + (prop, idx) => { const value = formatProperty(prop); if (prop.name === `${idx}`) return value; return `${prop.name}: ${value}`; }); if (this.preview.overflow) { - props.push('...'); + ArrayPrototypePush(props, '...'); } - const singleLine = props.join(', '); + const singleLine = ArrayPrototypeJoin(props, ', '); const propString = - singleLine.length > 60 ? props.join(',\n ') : singleLine; + singleLine.length > 60 ? + ArrayPrototypeJoin(props, ',\n ') : + singleLine; return this.subtype === 'array' ? `[ ${propString} ]` : `{ ${propString} }`; @@ -236,34 +281,39 @@ class RemoteObject { class ScopeSnapshot { constructor(scope, properties) { - Object.assign(this, scope); - this.properties = new Map(properties.map((prop) => { + ObjectAssign(this, scope); + this.properties = new SafeMap(); + this.completionGroup = ArrayPrototypeMap(properties, (prop) => { const value = new RemoteObject(prop.value); - return [prop.name, value]; - })); - this.completionGroup = properties.map((prop) => prop.name); + this.properties.set(prop.name, value); + return prop.name; + }); } [customInspectSymbol](depth, opts) { - const type = `${this.type[0].toUpperCase()}${this.type.slice(1)}`; + const type = StringPrototypeToUpperCase(this.type[0]) + + StringPrototypeSlice(this.type, 1); const name = this.name ? `<${this.name}>` : ''; const prefix = `${type}${name} `; - return utilInspect(this.properties, opts) - .replace(/^Map /, prefix); + return RegExpPrototypeSymbolReplace(/^Map /, + utilInspect(this.properties, opts), + prefix); } } function copyOwnProperties(target, source) { - Object.getOwnPropertyNames(source).forEach((prop) => { - const descriptor = Object.getOwnPropertyDescriptor(source, prop); - Object.defineProperty(target, prop, descriptor); - }); + ArrayPrototypeForEach( + ReflectOwnKeys(source), + (prop) => { + const desc = ReflectGetOwnPropertyDescriptor(source, prop); + ObjectDefineProperty(target, prop, desc); + }); } function aliasProperties(target, mapping) { - Object.keys(mapping).forEach((key) => { - const descriptor = Object.getOwnPropertyDescriptor(target, key); - Object.defineProperty(target, mapping[key], descriptor); + ArrayPrototypeForEach(ObjectKeys(mapping), (key) => { + const desc = ReflectGetOwnPropertyDescriptor(target, key); + ObjectDefineProperty(target, mapping[key], desc); }); } @@ -322,16 +372,14 @@ function createRepl(inspector) { return !script.isNative || isCurrentScript(script); } - return Object.keys(knownScripts) - .map((scriptId) => knownScripts[scriptId]) - .filter(isVisible) - .map((script) => { + return ArrayPrototypeJoin(ArrayPrototypeMap( + ArrayPrototypeFilter(ObjectValues(knownScripts), isVisible), + (script) => { const isCurrent = isCurrentScript(script); const { isNative, url } = script; const name = `${getRelativePath(url)}${isNative ? ' ' : ''}`; return `${isCurrent ? '*' : ' '} ${script.scriptId}: ${name}`; - }) - .join('\n'); + }), '\n'); } function listScripts(displayNatives = false) { @@ -349,19 +397,19 @@ function createRepl(inspector) { static createAndRegister({ profile }) { const p = new Profile(profile); - profiles.push(p); + ArrayPrototypePush(profiles, p); return p; } [customInspectSymbol](depth, { stylize }) { const { startTime, endTime } = this.data; - const MU = String.fromChar(956); + const MU = StringFromCharCode(956); return stylize(`[Profile ${endTime - startTime}${MU}s]`, 'special'); } save(filename = 'node.cpuprofile') { const absoluteFile = Path.resolve(filename); - const json = JSON.stringify(this.data); + const json = JSONStringify(this.data); FS.writeFileSync(absoluteFile, json); print('Saved profile to ' + absoluteFile); } @@ -369,68 +417,75 @@ function createRepl(inspector) { class SourceSnippet { constructor(location, delta, scriptSource) { - Object.assign(this, location); + ObjectAssign(this, location); this.scriptSource = scriptSource; this.delta = delta; } [customInspectSymbol](depth, options) { const { scriptId, lineNumber, columnNumber, delta, scriptSource } = this; - const start = Math.max(1, lineNumber - delta + 1); + const start = MathMax(1, lineNumber - delta + 1); const end = lineNumber + delta + 1; - const lines = scriptSource.split('\n'); - return lines.slice(start - 1, end).map((lineText, offset) => { - const i = start + offset; - const isCurrent = i === (lineNumber + 1); - - const markedLine = isCurrent ? - markSourceColumn(lineText, columnNumber, options.colors) : - lineText; - - let isBreakpoint = false; - knownBreakpoints.forEach(({ location }) => { - if (!location) return; - if (scriptId === location.scriptId && + const lines = StringPrototypeSplit(scriptSource, '\n'); + return ArrayPrototypeJoin( + ArrayPrototypeMap( + ArrayPrototypeSlice(lines, start - 1, end), + (lineText, offset) => { + const i = start + offset; + const isCurrent = i === (lineNumber + 1); + + const markedLine = isCurrent ? + markSourceColumn(lineText, columnNumber, options.colors) : + lineText; + + let isBreakpoint = false; + ArrayPrototypeForEach(knownBreakpoints, ({ location }) => { + if (!location) return; + if (scriptId === location.scriptId && i === (location.lineNumber + 1)) { - isBreakpoint = true; - } - }); + isBreakpoint = true; + } + }); - let prefixChar = ' '; - if (isCurrent) { - prefixChar = '>'; - } else if (isBreakpoint) { - prefixChar = '*'; - } - return `${leftPad(i, prefixChar, end)} ${markedLine}`; - }).join('\n'); + let prefixChar = ' '; + if (isCurrent) { + prefixChar = '>'; + } else if (isBreakpoint) { + prefixChar = '*'; + } + return `${leftPad(i, prefixChar, end)} ${markedLine}`; + }), '\n'); } } - function getSourceSnippet(location, delta = 5) { + async function getSourceSnippet(location, delta = 5) { const { scriptId } = location; - return Debugger.getScriptSource({ scriptId }) - .then(({ scriptSource }) => - new SourceSnippet(location, delta, scriptSource)); + const { scriptSource } = await Debugger.getScriptSource({ scriptId }); + return new SourceSnippet(location, delta, scriptSource); } class CallFrame { constructor(callFrame) { - Object.assign(this, callFrame); + ObjectAssign(this, callFrame); } loadScopes() { - return Promise.all( - this.scopeChain - .filter((scope) => scope.type !== 'global') - .map((scope) => { + return PromiseAll( + new SafeArrayIterator(ArrayPrototypeMap( + ArrayPrototypeFilter( + this.scopeChain, + (scope) => scope.type !== 'global' + ), + async (scope) => { const { objectId } = scope.object; - return Runtime.getProperties({ + const { result } = await Runtime.getProperties({ objectId, generatePreview: true, - }).then(({ result }) => new ScopeSnapshot(scope, result)); + }); + return new ScopeSnapshot(scope, result); }) + ) ); } @@ -441,69 +496,72 @@ function createRepl(inspector) { class Backtrace extends Array { [customInspectSymbol]() { - return this.map((callFrame, idx) => { - const { - location: { scriptId, lineNumber, columnNumber }, - functionName - } = callFrame; - const name = functionName || '(anonymous)'; - - const script = knownScripts[scriptId]; - const relativeUrl = + return ArrayPrototypeJoin( + ArrayPrototypeMap(this, (callFrame, idx) => { + const { + location: { scriptId, lineNumber, columnNumber }, + functionName + } = callFrame; + const name = functionName || '(anonymous)'; + + const script = knownScripts[scriptId]; + const relativeUrl = (script && getRelativePath(script.url)) || ''; - const frameLocation = + const frameLocation = `${relativeUrl}:${lineNumber + 1}:${columnNumber}`; - return `#${idx} ${name} ${frameLocation}`; - }).join('\n'); + return `#${idx} ${name} ${frameLocation}`; + }), '\n'); } static from(callFrames) { - return super.from(Array.from(callFrames).map((callFrame) => { - if (callFrame instanceof CallFrame) { - return callFrame; - } - return new CallFrame(callFrame); - })); + return FunctionPrototypeCall( + ArrayFrom, + this, + callFrames, + (callFrame) => + (callFrame instanceof CallFrame ? + callFrame : + new CallFrame(callFrame)) + ); } } function prepareControlCode(input) { if (input === '\n') return lastCommand; // Add parentheses: exec process.title => exec("process.title"); - const match = input.match(/^\s*exec\s+([^\n]*)/); + const match = RegExpPrototypeSymbolMatch(/^\s*exec\s+([^\n]*)/, input); if (match) { - lastCommand = `exec(${JSON.stringify(match[1])})`; + lastCommand = `exec(${JSONStringify(match[1])})`; } else { lastCommand = input; } return lastCommand; } - function evalInCurrentContext(code) { + async function evalInCurrentContext(code) { // Repl asked for scope variables if (code === '.scope') { if (!selectedFrame) { - return Promise.reject(new Error('Requires execution to be paused')); + throw new Error('Requires execution to be paused'); } - return selectedFrame.loadScopes().then((scopes) => { - return scopes.map((scope) => scope.completionGroup); - }); + const scopes = await selectedFrame.loadScopes(); + return ArrayPrototypeMap(scopes, (scope) => scope.completionGroup); } if (selectedFrame) { - return Debugger.evaluateOnCallFrame({ + return PromisePrototypeThen(Debugger.evaluateOnCallFrame({ callFrameId: selectedFrame.callFrameId, expression: code, objectGroup: 'node-inspect', generatePreview: true, - }).then(RemoteObject.fromEvalResult); + }), RemoteObject.fromEvalResult); } - return Runtime.evaluate({ + return PromisePrototypeThen(Runtime.evaluate({ expression: code, objectGroup: 'node-inspect', generatePreview: true, - }).then(RemoteObject.fromEvalResult); + }), RemoteObject.fromEvalResult); } function controlEval(input, context, filename, callback) { @@ -517,11 +575,16 @@ function createRepl(inspector) { const code = prepareControlCode(input); const result = vm.runInContext(code, context, filename); - if (result && typeof result.then === 'function') { - toCallback(result, returnToCallback); - return; + const then = result?.then; + if (typeof then === 'function') { + FunctionPrototypeCall( + then, result, + (result) => returnToCallback(null, result), + returnToCallback + ); + } else { + returnToCallback(null, result); } - returnToCallback(null, result); } catch (e) { returnToCallback(e); } @@ -534,76 +597,63 @@ function createRepl(inspector) { callback(error, result); } - try { - const result = evalInCurrentContext(input); - - if (result && typeof result.then === 'function') { - toCallback(result, returnToCallback); - return; - } - returnToCallback(null, result); - } catch (e) { - returnToCallback(e); - } + PromisePrototypeThen(evalInCurrentContext(input), + (result) => returnToCallback(null, result), + returnToCallback + ); } - function formatWatchers(verbose = false) { + async function formatWatchers(verbose = false) { if (!watchedExpressions.length) { - return Promise.resolve(''); + return ''; } const inspectValue = (expr) => - evalInCurrentContext(expr) - // .then(formatValue) - .catch((error) => `<${error.message}>`); + PromisePrototypeCatch(evalInCurrentContext(expr), + (error) => `<${error.message}>`); const lastIndex = watchedExpressions.length - 1; - return Promise.all(watchedExpressions.map(inspectValue)) - .then((values) => { - const lines = watchedExpressions - .map((expr, idx) => { - const prefix = `${leftPad(idx, ' ', lastIndex)}: ${expr} =`; - const value = inspect(values[idx]); - if (value.indexOf('\n') === -1) { - return `${prefix} ${value}`; - } - return `${prefix}\n ${value.split('\n').join('\n ')}`; - }); - return lines.join('\n'); - }) - .then((valueList) => { - return verbose ? `Watchers:\n${valueList}\n` : valueList; - }); + const values = await PromiseAll(new SafeArrayIterator( + ArrayPrototypeMap(watchedExpressions, inspectValue))); + const lines = ArrayPrototypeMap(watchedExpressions, (expr, idx) => { + const prefix = `${leftPad(idx, ' ', lastIndex)}: ${expr} =`; + const value = inspect(values[idx], { colors: true }); + if (!StringPrototypeIncludes(value, '\n')) { + return `${prefix} ${value}`; + } + return `${prefix}\n ${RegExpPrototypeSymbolReplace(/\n/g, value, '\n ')}`; + }); + const valueList = ArrayPrototypeJoin(lines, '\n'); + return verbose ? `Watchers:\n${valueList}\n` : valueList; } function watchers(verbose = false) { - return formatWatchers(verbose).then(print); + return PromisePrototypeThen(formatWatchers(verbose), print); } // List source code function list(delta = 5) { - return selectedFrame.list(delta) - .then(null, (error) => { - print('You can\'t list source code right now'); - throw error; - }); + return selectedFrame.list(delta).then(null, (error) => { + print("You can't list source code right now"); + throw error; + }); } function handleBreakpointResolved({ breakpointId, location }) { const script = knownScripts[location.scriptId]; const scriptUrl = script && script.url; if (scriptUrl) { - Object.assign(location, { scriptUrl }); + ObjectAssign(location, { scriptUrl }); } - const isExisting = knownBreakpoints.some((bp) => { + const isExisting = ArrayPrototypeSome(knownBreakpoints, (bp) => { if (bp.breakpointId === breakpointId) { - Object.assign(bp, { location }); + ObjectAssign(bp, { location }); return true; } return false; }); if (!isExisting) { - knownBreakpoints.push({ breakpointId, location }); + ArrayPrototypePush(knownBreakpoints, { breakpointId, location }); } } @@ -619,9 +669,11 @@ function createRepl(inspector) { const scriptUrl = script ? script.url : location.scriptUrl; return `${getRelativePath(scriptUrl)}:${location.lineNumber + 1}`; } - const breaklist = knownBreakpoints - .map((bp, idx) => `#${idx} ${formatLocation(bp.location)}`) - .join('\n'); + const breaklist = ArrayPrototypeJoin( + ArrayPrototypeMap( + knownBreakpoints, + (bp, idx) => `#${idx} ${formatLocation(bp.location)}`), + '\n'); print(breaklist); } @@ -638,9 +690,9 @@ function createRepl(inspector) { // setBreakpoint(): set breakpoint at current location if (script === undefined) { - return Debugger - .setBreakpoint({ location: getCurrentLocation(), condition }) - .then(registerBreakpoint); + return PromisePrototypeThen( + Debugger.setBreakpoint({ location: getCurrentLocation(), condition }), + registerBreakpoint); } // setBreakpoint(line): set breakpoint in current script at specific line @@ -649,8 +701,9 @@ function createRepl(inspector) { scriptId: getCurrentLocation().scriptId, lineNumber: script - 1, }; - return Debugger.setBreakpoint({ location, condition }) - .then(registerBreakpoint); + return PromisePrototypeThen( + Debugger.setBreakpoint({ location, condition }), + registerBreakpoint); } if (typeof script !== 'string') { @@ -658,7 +711,7 @@ function createRepl(inspector) { } // setBreakpoint('fn()'): Break when a function is called - if (script.endsWith('()')) { + if (StringPrototypeEndsWith(script, '()')) { const debugExpr = `debug(${script.slice(0, -2)})`; const debugCall = selectedFrame ? Debugger.evaluateOnCallFrame({ @@ -670,7 +723,7 @@ function createRepl(inspector) { expression: debugExpr, includeCommandLineAPI: true, }); - return debugCall.then(({ result, wasThrown }) => { + return PromisePrototypeThen(debugCall, ({ result, wasThrown }) => { if (wasThrown) return convertResultToError(result); return undefined; // This breakpoint can't be removed the same way }); @@ -682,15 +735,15 @@ function createRepl(inspector) { if (knownScripts[script]) { scriptId = script; } else { - for (const id of Object.keys(knownScripts)) { + ArrayPrototypeForEach(ObjectKeys(knownScripts), (id) => { const scriptUrl = knownScripts[id].url; - if (scriptUrl && scriptUrl.indexOf(script) !== -1) { + if (scriptUrl && StringPrototypeIncludes(scriptUrl, script)) { if (scriptId !== null) { ambiguous = true; } scriptId = id; } - } + }); } if (ambiguous) { @@ -704,19 +757,25 @@ function createRepl(inspector) { if (scriptId !== null) { const location = { scriptId, lineNumber: line - 1 }; - return Debugger.setBreakpoint({ location, condition }) - .then(registerBreakpoint); + return PromisePrototypeThen( + Debugger.setBreakpoint({ location, condition }), + registerBreakpoint); } - const escapedPath = script.replace(/([/\\.?*()^${}|[\]])/g, '\\$1'); + const escapedPath = RegExpPrototypeSymbolReplace(/([/\\.?*()^${}|[\]])/g, + script, '\\$1'); const urlRegex = `^(.*[\\/\\\\])?${escapedPath}$`; - return Debugger - .setBreakpointByUrl({ urlRegex, lineNumber: line - 1, condition }) - .then((bp) => { + return PromisePrototypeThen( + Debugger.setBreakpointByUrl({ + urlRegex, + lineNumber: line - 1, + condition, + }), + (bp) => { // TODO: handle bp.locations in case the regex matches existing files if (!bp.location) { // Fake it for now. - Object.assign(bp, { + ObjectAssign(bp, { actualLocation: { scriptUrl: `.*/${script}$`, lineNumber: line - 1, @@ -728,41 +787,46 @@ function createRepl(inspector) { } function clearBreakpoint(url, line) { - const breakpoint = knownBreakpoints.find(({ location }) => { + const breakpoint = ArrayPrototypeFind(knownBreakpoints, ({ location }) => { if (!location) return false; const script = knownScripts[location.scriptId]; if (!script) return false; return ( - script.url.indexOf(url) !== -1 && (location.lineNumber + 1) === line + StringPrototypeIncludes(script.url, url) && + (location.lineNumber + 1) === line ); }); if (!breakpoint) { print(`Could not find breakpoint at ${url}:${line}`); - return Promise.resolve(); + return PromiseResolve(); } - return Debugger.removeBreakpoint({ breakpointId: breakpoint.breakpointId }) - .then(() => { - const idx = knownBreakpoints.indexOf(breakpoint); - knownBreakpoints.splice(idx, 1); + return PromisePrototypeThen( + Debugger.removeBreakpoint({ breakpointId: breakpoint.breakpointId }), + () => { + const idx = ArrayPrototypeIndexOf(knownBreakpoints, breakpoint); + ArrayPrototypeSplice(knownBreakpoints, idx, 1); }); } function restoreBreakpoints() { - const lastBreakpoints = knownBreakpoints.slice(); - knownBreakpoints.length = 0; - const newBreakpoints = lastBreakpoints - .filter(({ location }) => !!location.scriptUrl) - .map(({ location }) => - setBreakpoint(location.scriptUrl, location.lineNumber + 1)); - if (!newBreakpoints.length) return Promise.resolve(); - return Promise.all(newBreakpoints).then((results) => { - print(`${results.length} breakpoints restored.`); - }); + const lastBreakpoints = ArrayPrototypeSplice(knownBreakpoints, 0); + const newBreakpoints = ArrayPrototypeMap( + ArrayPrototypeFilter(lastBreakpoints, + ({ location }) => !!location.scriptUrl), + ({ location }) => setBreakpoint(location.scriptUrl, + location.lineNumber + 1)); + if (!newBreakpoints.length) return PromiseResolve(); + return PromisePrototypeThen( + PromiseAll(new SafeArrayIterator(newBreakpoints)), + (results) => { + print(`${results.length} breakpoints restored.`); + }); } function setPauseOnExceptions(state) { - return Debugger.setPauseOnExceptions({ state }) - .then(() => { + return PromisePrototypeThen( + Debugger.setPauseOnExceptions({ state }), + () => { pauseOnExceptionState = state; }); } @@ -788,13 +852,13 @@ function createRepl(inspector) { const header = `${breakType} in ${scriptUrl}:${lineNumber + 1}`; inspector.suspendReplWhile(() => - Promise.all([formatWatchers(true), selectedFrame.list(2)]) - .then(({ 0: watcherList, 1: context }) => { - if (watcherList) { - return `${watcherList}\n${inspect(context)}`; - } - return inspect(context); - }).then((breakContext) => { + PromisePrototypeThen( + PromiseAll(new SafeArrayIterator( + [formatWatchers(true), selectedFrame.list(2)])), + ({ 0: watcherList, 1: context }) => { + const breakContext = watcherList ? + `${watcherList}\n${inspect(context)}` : + inspect(context); print(`${header}\n${breakContext}`); })); }); @@ -817,15 +881,15 @@ function createRepl(inspector) { Profiler.on('consoleProfileFinished', ({ profile }) => { Profile.createAndRegister({ profile }); - print([ - 'Captured new CPU profile.', - `Access it with profiles[${profiles.length - 1}]`, - ].join('\n')); + print( + 'Captured new CPU profile.\n' + + `Access it with profiles[${profiles.length - 1}]` + ); }); function initializeContext(context) { - inspector.domainNames.forEach((domain) => { - Object.defineProperty(context, domain, { + ArrayPrototypeForEach(inspector.domainNames, (domain) => { + ObjectDefineProperty(context, domain, { value: inspector[domain], enumerable: true, configurable: true, @@ -891,8 +955,8 @@ function createRepl(inspector) { }, get profileEnd() { - return Profiler.stop() - .then(Profile.createAndRegister); + return PromisePrototypeThen(Profiler.stop(), + Profile.createAndRegister); }, get profiles() { @@ -941,8 +1005,9 @@ function createRepl(inspector) { HeapProfiler.on('addHeapSnapshotChunk', onChunk); print('Heap snapshot: 0/0', false); - HeapProfiler.takeHeapSnapshot({ reportProgress: true }) - .then(onResolve, onReject); + PromisePrototypeThen( + HeapProfiler.takeHeapSnapshot({ reportProgress: true }), + onResolve, onReject); }); }, @@ -951,21 +1016,22 @@ function createRepl(inspector) { }, watch(expr) { - watchedExpressions.push(expr); + ArrayPrototypePush(watchedExpressions, expr); }, unwatch(expr) { - const index = watchedExpressions.indexOf(expr); + const index = ArrayPrototypeIndexOf(watchedExpressions, expr); // Unwatch by expression // or // Unwatch by watcher number - watchedExpressions.splice(index !== -1 ? index : +expr, 1); + ArrayPrototypeSplice(watchedExpressions, + index !== -1 ? index : +expr, 1); }, get repl() { // Don't display any default messages - const listeners = repl.listeners('SIGINT').slice(0); + const listeners = ArrayPrototypeSlice(repl.listeners('SIGINT')); repl.removeAllListeners('SIGINT'); const oldContext = repl.context; @@ -973,7 +1039,7 @@ function createRepl(inspector) { exitDebugRepl = () => { // Restore all listeners process.nextTick(() => { - listeners.forEach((listener) => { + ArrayPrototypeForEach(listeners, (listener) => { repl.on('SIGINT', listener); }); }); @@ -1016,11 +1082,11 @@ function createRepl(inspector) { }, get version() { - return Runtime.evaluate({ + return PromisePrototypeThen(Runtime.evaluate({ expression: 'process.versions.v8', contextId: 1, returnByValue: true, - }).then(({ result }) => { + }), ({ result }) => { print(result.value); }); }, @@ -1045,18 +1111,17 @@ function createRepl(inspector) { aliasProperties(context, SHORTCUTS); } - function initAfterStart() { - return Runtime.enable() - .then(() => Profiler.enable()) - .then(() => Profiler.setSamplingInterval({ interval: 100 })) - .then(() => Debugger.enable()) - .then(() => Debugger.setPauseOnExceptions({ state: 'none' })) - .then(() => Debugger.setAsyncCallStackDepth({ maxDepth: 0 })) - .then(() => Debugger.setBlackboxPatterns({ patterns: [] })) - .then(() => - Debugger.setPauseOnExceptions({ state: pauseOnExceptionState })) - .then(() => restoreBreakpoints()) - .then(() => Runtime.runIfWaitingForDebugger()); + async function initAfterStart() { + await Runtime.enable(); + await Profiler.enable(); + await Profiler.setSamplingInterval({ interval: 100 }); + await Debugger.enable(); + await Debugger.setPauseOnExceptions({ state: 'none' }); + await Debugger.setAsyncCallStackDepth({ maxDepth: 0 }); + await Debugger.setBlackboxPatterns({ patterns: [] }); + await Debugger.setPauseOnExceptions({ state: pauseOnExceptionState }); + await restoreBreakpoints(); + return Runtime.runIfWaitingForDebugger(); } return async function startRepl() { From f41d0103fdcac29d52d5e55d9dd4cd821f30fd7a Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 29 May 2021 19:37:01 -0700 Subject: [PATCH 16/24] debugger: removed unused function argument PR-URL: https://github.com/nodejs/node/pull/38850 Reviewed-By: Antoine du Hamel Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- lib/internal/inspector/inspect_repl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/inspector/inspect_repl.js b/lib/internal/inspector/inspect_repl.js index 67b7f73aa1b25e..3cb4d52f43aaf1 100644 --- a/lib/internal/inspector/inspect_repl.js +++ b/lib/internal/inspector/inspect_repl.js @@ -617,7 +617,7 @@ function createRepl(inspector) { ArrayPrototypeMap(watchedExpressions, inspectValue))); const lines = ArrayPrototypeMap(watchedExpressions, (expr, idx) => { const prefix = `${leftPad(idx, ' ', lastIndex)}: ${expr} =`; - const value = inspect(values[idx], { colors: true }); + const value = inspect(values[idx]); if (!StringPrototypeIncludes(value, '\n')) { return `${prefix} ${value}`; } From 7a5e9021ebfb8ca5a43cc70de3088eb924084c45 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 12 Jun 2021 17:13:14 -0700 Subject: [PATCH 17/24] errors: add ERR_DEBUGGER_ERROR PR-URL: https://github.com/nodejs/node/pull/39024 Reviewed-By: Antoine du Hamel Reviewed-By: Luigi Pinca Reviewed-By: Jan Krems --- doc/api/errors.md | 9 +++++++++ lib/internal/errors.js | 1 + 2 files changed, 10 insertions(+) diff --git a/doc/api/errors.md b/doc/api/errors.md index 7828d5a688e5c1..68c91587ffdebe 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -876,6 +876,14 @@ An unknown cipher was specified. An unknown Diffie-Hellman group name was given. See [`crypto.getDiffieHellman()`][] for a list of valid group names. + +### `ERR_DEBUGGER_ERROR` + + +An error occurred with the [debugger][]. + ### `ERR_DIR_CLOSED` @@ -2599,6 +2607,7 @@ closed. [`util.getSystemErrorName(error.errno)`]: util.md#util_util_getsystemerrorname_err [`zlib`]: zlib.md [crypto digest algorithm]: crypto.md#crypto_crypto_gethashes +[debugger]: debugger.md [define a custom subpath]: packages.md#packages_subpath_exports [domains]: domain.md [event emitter-based]: events.md#events_class_eventemitter diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 31f569f5e57e6a..5e6c57efcadb39 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -831,6 +831,7 @@ E('ERR_CRYPTO_SCRYPT_INVALID_PARAMETER', 'Invalid scrypt parameter', Error); E('ERR_CRYPTO_SCRYPT_NOT_SUPPORTED', 'Scrypt algorithm not supported', Error); // Switch to TypeError. The current implementation does not seem right. E('ERR_CRYPTO_SIGN_KEY_REQUIRED', 'No key provided to sign', Error); +E('ERR_DEBUGGER_ERROR', '%s', Error); E('ERR_DIR_CLOSED', 'Directory handle was closed', Error); E('ERR_DIR_CONCURRENT_OPERATION', 'Cannot do synchronous work on directory handle with concurrent ' + From beb3dce4248edf3db348b30ed93cc7d493638f1d Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 12 Jun 2021 17:35:49 -0700 Subject: [PATCH 18/24] debugger: use ERR_DEBUGGER_ERROR in debugger client PR-URL: https://github.com/nodejs/node/pull/39024 Reviewed-By: Antoine du Hamel Reviewed-By: Luigi Pinca Reviewed-By: Jan Krems --- lib/internal/inspector/inspect_client.js | 32 +++++++++++++----------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/internal/inspector/inspect_client.js b/lib/internal/inspector/inspect_client.js index 4c89c56af93ef6..8fc9011ca888ed 100644 --- a/lib/internal/inspector/inspect_client.js +++ b/lib/internal/inspector/inspect_client.js @@ -1,11 +1,7 @@ -// TODO(aduh95): use errors exported by the internal/errors module -/* eslint-disable no-restricted-syntax */ - 'use strict'; const { ArrayPrototypePush, - Error, ErrorCaptureStackTrace, FunctionPrototypeBind, JSONParse, @@ -15,6 +11,7 @@ const { } = primordials; const Buffer = require('buffer').Buffer; +const { ERR_DEBUGGER_ERROR } = require('internal/errors').codes; const { EventEmitter } = require('events'); const http = require('http'); const URL = require('url'); @@ -39,7 +36,7 @@ const kEightBytePayloadLengthField = 127; const kMaskingKeyWidthInBytes = 4; function unpackError({ code, message, data }) { - const err = new Error(`${message} - ${data}`); + const err = new ERR_DEBUGGER_ERROR(`${message} - ${data}`); err.code = code; ErrorCaptureStackTrace(err, unpackError); return err; @@ -101,14 +98,14 @@ function decodeFrameHybi17(data) { const masked = (secondByte & kMaskBit) !== 0; const compressed = reserved1; if (compressed) { - throw new Error('Compressed frames not supported'); + throw new ERR_DEBUGGER_ERROR('Compressed frames not supported'); } if (!final || reserved2 || reserved3) { - throw new Error('Only compression extension is supported'); + throw new ERR_DEBUGGER_ERROR('Only compression extension is supported'); } if (masked) { - throw new Error('Masked server frame - not supported'); + throw new ERR_DEBUGGER_ERROR('Masked server frame - not supported'); } let closed = false; @@ -119,7 +116,7 @@ function decodeFrameHybi17(data) { case kOpCodeText: break; default: - throw new Error(`Unsupported op code ${opCode}`); + throw new ERR_DEBUGGER_ERROR(`Unsupported op code ${opCode}`); } let payloadLength = secondByte & kPayloadLengthMask; @@ -183,7 +180,9 @@ class Client extends EventEmitter { debuglog('< %s', payloadStr); const lastChar = payloadStr[payloadStr.length - 1]; if (payloadStr[0] !== '{' || lastChar !== '}') { - throw new Error(`Payload does not look like JSON: ${payloadStr}`); + throw new ERR_DEBUGGER_ERROR( + `Payload does not look like JSON: ${payloadStr}` + ); } let payload; try { @@ -204,7 +203,7 @@ class Client extends EventEmitter { this.emit('debugEvent', method, params); this.emit(method, params); } else { - throw new Error(`Unsupported response: ${payloadStr}`); + throw new ERR_DEBUGGER_ERROR(`Unsupported response: ${payloadStr}`); } } } @@ -226,7 +225,7 @@ class Client extends EventEmitter { callMethod(method, params) { return new Promise((resolve, reject) => { if (!this._socket) { - reject(new Error('Use `run` to start the app again.')); + reject(new ERR_DEBUGGER_ERROR('Use `run` to start the app again.')); return; } const data = { id: ++this._lastId, method, params }; @@ -254,14 +253,17 @@ class Client extends EventEmitter { function parseChunks() { const resBody = Buffer.concat(chunks).toString(); if (httpRes.statusCode !== 200) { - reject(new Error(`Unexpected ${httpRes.statusCode}: ${resBody}`)); + reject(new ERR_DEBUGGER_ERROR( + `Unexpected ${httpRes.statusCode}: ${resBody}` + )); return; } try { resolve(JSONParse(resBody)); } catch { - reject(new Error(`Response didn't contain JSON: ${resBody}`)); - + reject(new ERR_DEBUGGER_ERROR( + `Response didn't contain JSON: ${resBody}` + )); } } From a4c42b5291b52b76cb2eee393ec679d152b19be2 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 13 Jun 2021 05:00:09 -0700 Subject: [PATCH 19/24] debugger: use error codes in debugger REPL PR-URL: https://github.com/nodejs/node/pull/39024 Reviewed-By: Antoine du Hamel Reviewed-By: Luigi Pinca Reviewed-By: Jan Krems --- lib/internal/inspector/inspect_repl.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/internal/inspector/inspect_repl.js b/lib/internal/inspector/inspect_repl.js index 3cb4d52f43aaf1..5393cb32718300 100644 --- a/lib/internal/inspector/inspect_repl.js +++ b/lib/internal/inspector/inspect_repl.js @@ -1,5 +1,5 @@ // TODO(trott): enable ESLint -/* eslint-disable getter-return, no-restricted-syntax */ +/* eslint-disable getter-return */ 'use strict'; @@ -18,7 +18,6 @@ const { ArrayPrototypeSome, ArrayPrototypeSplice, Date, - Error, FunctionPrototypeCall, JSONStringify, MathMax, @@ -47,9 +46,12 @@ const { StringPrototypeStartsWith, StringPrototypeToUpperCase, StringPrototypeTrim, - TypeError, } = primordials; +const { ERR_DEBUGGER_ERROR } = require('internal/errors').codes; + +const { validateString } = require('internal/validators'); + const FS = require('fs'); const Path = require('path'); const Repl = require('repl'); @@ -176,7 +178,7 @@ function extractErrorMessage(stack) { function convertResultToError(result) { const { className, description } = result; - const err = new Error(extractErrorMessage(description)); + const err = new ERR_DEBUGGER_ERROR(extractErrorMessage(description)); err.stack = description; ObjectDefineProperty(err, 'name', { value: className }); return err; @@ -357,7 +359,7 @@ function createRepl(inspector) { function getCurrentLocation() { if (!selectedFrame) { - throw new Error('Requires execution to be paused'); + throw new ERR_DEBUGGER_ERROR('Requires execution to be paused'); } return selectedFrame.location; } @@ -543,7 +545,7 @@ function createRepl(inspector) { // Repl asked for scope variables if (code === '.scope') { if (!selectedFrame) { - throw new Error('Requires execution to be paused'); + throw new ERR_DEBUGGER_ERROR('Requires execution to be paused'); } const scopes = await selectedFrame.loadScopes(); return ArrayPrototypeMap(scopes, (scope) => scope.completionGroup); @@ -706,9 +708,7 @@ function createRepl(inspector) { registerBreakpoint); } - if (typeof script !== 'string') { - throw new TypeError(`setBreakpoint() expects a string, got ${script}`); - } + validateString(script, 'script'); // setBreakpoint('fn()'): Break when a function is called if (StringPrototypeEndsWith(script, '()')) { From 584f779f513729a5984c55b2babb9391182f2826 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 13 Jun 2021 05:14:01 -0700 Subject: [PATCH 20/24] errors: add ERR_DEBUGGER_STARTUP_ERROR PR-URL: https://github.com/nodejs/node/pull/39024 Reviewed-By: Antoine du Hamel Reviewed-By: Luigi Pinca Reviewed-By: Jan Krems --- doc/api/errors.md | 8 ++++++++ lib/internal/errors.js | 1 + 2 files changed, 9 insertions(+) diff --git a/doc/api/errors.md b/doc/api/errors.md index 68c91587ffdebe..7b6b406de0fa54 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -884,6 +884,14 @@ added: REPLACEME An error occurred with the [debugger][]. + +### `ERR_DEBUGGER_STARTUP_ERROR` + + +The [debugger][] timed out waiting for the required host/port to be free. + ### `ERR_DIR_CLOSED` diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 5e6c57efcadb39..441c4f2f317171 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -832,6 +832,7 @@ E('ERR_CRYPTO_SCRYPT_NOT_SUPPORTED', 'Scrypt algorithm not supported', Error); // Switch to TypeError. The current implementation does not seem right. E('ERR_CRYPTO_SIGN_KEY_REQUIRED', 'No key provided to sign', Error); E('ERR_DEBUGGER_ERROR', '%s', Error); +E('ERR_DEBUGGER_STARTUP_ERROR', '%s', Error); E('ERR_DIR_CLOSED', 'Directory handle was closed', Error); E('ERR_DIR_CONCURRENT_OPERATION', 'Cannot do synchronous work on directory handle with concurrent ' + From f5dd504b2ec3162d43e96cde157ca0c070cd900c Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 13 Jun 2021 05:53:05 -0700 Subject: [PATCH 21/24] debugger: use ERR_DEBUGGER_STARTUP_ERROR in _inspect.js PR-URL: https://github.com/nodejs/node/pull/39024 Reviewed-By: Antoine du Hamel Reviewed-By: Luigi Pinca Reviewed-By: Jan Krems --- lib/internal/inspector/_inspect.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/internal/inspector/_inspect.js b/lib/internal/inspector/_inspect.js index 4786a478fe14d8..526545d3abc761 100644 --- a/lib/internal/inspector/_inspect.js +++ b/lib/internal/inspector/_inspect.js @@ -8,7 +8,6 @@ const { ArrayPrototypePop, ArrayPrototypeShift, ArrayPrototypeSlice, - Error, FunctionPrototypeBind, Number, Promise, @@ -50,12 +49,7 @@ const { 0: InspectClient, 1: createRepl } = const debuglog = util.debuglog('inspect'); -class StartupError extends Error { - constructor(message) { - super(message); - this.name = 'StartupError'; - } -} +const { ERR_DEBUGGER_STARTUP_ERROR } = require('internal/errors').codes; async function portIsFree(host, port, timeout = 9999) { if (port === 0) return; // Binding to a random port. @@ -70,7 +64,7 @@ async function portIsFree(host, port, timeout = 9999) { while (true) { await asyncIterator.next(); if (signal.aborted) { - throw new StartupError( // eslint-disable-line no-restricted-syntax + throw new ERR_DEBUGGER_STARTUP_ERROR( `Timeout (${timeout}) waiting for ${host}:${port} to be free`); } const error = await new Promise((resolve) => { @@ -346,7 +340,7 @@ function startInspect(argv = ArrayPrototypeSlice(process.argv, 2), stdin.resume(); function handleUnexpectedError(e) { - if (!(e instanceof StartupError)) { + if (e.code !== 'ERR_DEBUGGER_STARTUP_ERROR') { console.error('There was an internal error in Node.js. ' + 'Please report this bug.'); console.error(e.message); From 2e8360ed67a5e0e97faf72658e83479e2a5f903f Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 18 Jun 2021 22:27:10 -0700 Subject: [PATCH 22/24] debugger: rename internal library for clarity When I moved these files from node-inspect to Node.js core, I put them in lib/internal/inspector. That was a mistake. They should be in lib/internal/debugger. PR-URL: https://github.com/nodejs/node/pull/39080 Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig --- lib/internal/{inspector => debugger}/_inspect.js | 4 ++-- lib/internal/{inspector => debugger}/inspect_client.js | 0 lib/internal/{inspector => debugger}/inspect_repl.js | 0 lib/internal/main/inspect.js | 2 +- node.gyp | 6 +++--- 5 files changed, 6 insertions(+), 6 deletions(-) rename lib/internal/{inspector => debugger}/_inspect.js (98%) rename lib/internal/{inspector => debugger}/inspect_client.js (100%) rename lib/internal/{inspector => debugger}/inspect_repl.js (100%) diff --git a/lib/internal/inspector/_inspect.js b/lib/internal/debugger/_inspect.js similarity index 98% rename from lib/internal/inspector/_inspect.js rename to lib/internal/debugger/_inspect.js index 526545d3abc761..c8e38512bb8297 100644 --- a/lib/internal/inspector/_inspect.js +++ b/lib/internal/debugger/_inspect.js @@ -43,8 +43,8 @@ const console = require('internal/console/global'); const { 0: InspectClient, 1: createRepl } = [ - require('internal/inspector/inspect_client'), - require('internal/inspector/inspect_repl'), + require('internal/debugger/inspect_client'), + require('internal/debugger/inspect_repl'), ]; const debuglog = util.debuglog('inspect'); diff --git a/lib/internal/inspector/inspect_client.js b/lib/internal/debugger/inspect_client.js similarity index 100% rename from lib/internal/inspector/inspect_client.js rename to lib/internal/debugger/inspect_client.js diff --git a/lib/internal/inspector/inspect_repl.js b/lib/internal/debugger/inspect_repl.js similarity index 100% rename from lib/internal/inspector/inspect_repl.js rename to lib/internal/debugger/inspect_repl.js diff --git a/lib/internal/main/inspect.js b/lib/internal/main/inspect.js index 10e7cbf2c2b48a..731ff1cd0dc7f0 100644 --- a/lib/internal/main/inspect.js +++ b/lib/internal/main/inspect.js @@ -18,5 +18,5 @@ markBootstrapComplete(); // Start the debugger agent. process.nextTick(() => { - require('internal/inspector/_inspect').start(); + require('internal/debugger/_inspect').start(); }); diff --git a/node.gyp b/node.gyp index ce902069ed6bac..8ba0dfebe890e8 100644 --- a/node.gyp +++ b/node.gyp @@ -125,6 +125,9 @@ 'lib/internal/crypto/sig.js', 'lib/internal/crypto/util.js', 'lib/internal/constants.js', + 'lib/internal/debugger/_inspect.js', + 'lib/internal/debugger/inspect_client.js', + 'lib/internal/debugger/inspect_repl.js', 'lib/internal/dgram.js', 'lib/internal/dns/promises.js', 'lib/internal/dns/utils.js', @@ -148,9 +151,6 @@ 'lib/internal/heap_utils.js', 'lib/internal/histogram.js', 'lib/internal/idna.js', - 'lib/internal/inspector/_inspect.js', - 'lib/internal/inspector/inspect_client.js', - 'lib/internal/inspector/inspect_repl.js', 'lib/internal/inspector_async_hook.js', 'lib/internal/js_stream_socket.js', 'lib/internal/linkedlist.js', From 1211825d8e3a90c764da1dbc1a23f92459a89ac2 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Tue, 20 Jul 2021 18:01:39 +0200 Subject: [PATCH 23/24] fixup! lib: add primordials.SafeArrayIterator --- test/parallel/test-require-delete-array-iterator.js | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 test/parallel/test-require-delete-array-iterator.js diff --git a/test/parallel/test-require-delete-array-iterator.js b/test/parallel/test-require-delete-array-iterator.js deleted file mode 100644 index 5424ef8b75da9d..00000000000000 --- a/test/parallel/test-require-delete-array-iterator.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; - -const common = require('../common'); - - -const ArrayIteratorPrototype = - Object.getPrototypeOf(Array.prototype[Symbol.iterator]()); - -delete Array.prototype[Symbol.iterator]; -delete ArrayIteratorPrototype.next; - -require('../common/fixtures'); -import('../fixtures/es-modules/test-esm-ok.mjs').then(common.mustCall()); From 9cd07e19d9ef04693936432ba5b01ced68838095 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Tue, 20 Jul 2021 19:09:09 +0200 Subject: [PATCH 24/24] fixup! debugger: add usage example for `--port` --- test/parallel/test-debug-usage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-debug-usage.js b/test/parallel/test-debug-usage.js index eb9594f236b35c..fcf2d8edb944e0 100644 --- a/test/parallel/test-debug-usage.js +++ b/test/parallel/test-debug-usage.js @@ -11,7 +11,7 @@ child.stderr.setEncoding('utf8'); const expectedLines = [ /^\(node:\d+\) \[DEP0068\] DeprecationWarning:/, - /Usage: .*node.* debug script\.js\r?\n .*node.* debug :\r?\n .*node.* debug -p \r?\n$/, + /Usage: .*node.* debug script\.js\r?\n .*node.* debug :\r?\n .*node.* debug --port=\r?\n .*node.* debug -p \r?\n$/, ]; let actualUsageMessage = '';