From 7ab905036347774d45a6cc192368870d4ccc7b29 Mon Sep 17 00:00:00 2001 From: RedYetiDev <38299977+RedYetiDev@users.noreply.github.com> Date: Sat, 13 Apr 2024 08:39:14 -0400 Subject: [PATCH] Replace deps with native functions: chalk, strip-ansi, ws (and make some little changes) --- package.json | 5 +-- src/highlight.js | 63 +++++++++++++++++++------------------ src/index.js | 81 ++++++++++++++++++++++-------------------------- src/inspector.js | 79 ++++++++++++++++++++++++++-------------------- src/stub.js | 14 +-------- 5 files changed, 117 insertions(+), 125 deletions(-) diff --git a/package.json b/package.json index bb7bfd9..8d8ef18 100644 --- a/package.json +++ b/package.json @@ -29,10 +29,7 @@ "dependencies": { "acorn": "^8.7.1", "acorn-loose": "^8.3.0", - "chalk": "^4.1.2", - "emphasize": "^4.2.0", - "strip-ansi": "^6.0.1", - "ws": "^7.3.0" + "emphasize": "^4.2.0" }, "private": true } diff --git a/src/highlight.js b/src/highlight.js index 7e31325..2d1c017 100644 --- a/src/highlight.js +++ b/src/highlight.js @@ -1,43 +1,46 @@ 'use strict'; const emphasize = require('emphasize'); -const chalk = require('chalk'); +const util = require('util'); + +function makeStyled([start, end]) { + return (s) => `\x1b[${start}m${s}\x1b[${end}m`; +} -const windows = process.platform === 'win32'; const sheet = { - 'comment': chalk.gray, - 'quote': chalk.gray, + 'comment': makeStyled(util.inspect.colors.grey), + 'quote': makeStyled(util.inspect.colors.grey), - 'keyword': chalk.green, - 'addition': chalk.green, + 'keyword': makeStyled(util.inspect.colors.green), + 'addition': makeStyled(util.inspect.colors.green), - 'number': windows ? chalk.yellow : chalk.blue, - 'string': chalk.green, - 'meta meta-string': chalk.cyan, - 'literal': chalk.cyan, - 'doctag': chalk.cyan, - 'regexp': chalk.cyan, + 'number': makeStyled(util.inspect.colors.yellow), + 'string': makeStyled(util.inspect.colors.green), + 'meta meta-string': makeStyled(util.inspect.colors.cyan), + 'literal': makeStyled(util.inspect.colors.cyan), + 'doctag': makeStyled(util.inspect.colors.cyan), + 'regexp': makeStyled(util.inspect.colors.cyan), 'attribute': undefined, 'attr': undefined, - 'variable': chalk.yellow, - 'template-variable': chalk.yellow, - 'class title': chalk.yellow, - 'type': chalk.yellow, - - 'symbol': chalk.magenta, - 'bullet': chalk.magenta, - 'subst': chalk.magenta, - 'meta': chalk.magenta, - 'meta keyword': chalk.magenta, - 'link': chalk.magenta, - - 'built_in': chalk.cyan, - 'deletion': chalk.red, - - 'emphasis': chalk.italic, - 'strong': chalk.bold, - 'formula': chalk.inverse, + 'variable': makeStyled(util.inspect.colors.yellow), + 'template-variable': makeStyled(util.inspect.colors.yellow), + 'class title': makeStyled(util.inspect.colors.yellow), + 'type': makeStyled(util.inspect.colors.yellow), + + 'symbol': makeStyled(util.inspect.colors.magenta), + 'bullet': makeStyled(util.inspect.colors.magenta), + 'subst': makeStyled(util.inspect.colors.magenta), + 'meta': makeStyled(util.inspect.colors.magenta), + 'meta keyword': makeStyled(util.inspect.colors.magenta), + 'link': makeStyled(util.inspect.colors.magenta), + + 'built_in': makeStyled(util.inspect.colors.cyan), + 'deletion': makeStyled(util.inspect.colors.red), + + 'emphasis': makeStyled(util.inspect.colors.italic), + 'strong': makeStyled(util.inspect.colors.bold), + 'formula': makeStyled(util.inspect.colors.inverse), }; module.exports = (s) => diff --git a/src/index.js b/src/index.js index 12ea2b6..5a8de35 100755 --- a/src/index.js +++ b/src/index.js @@ -3,35 +3,43 @@ 'use strict'; const { createInterface, clearScreenDown } = require('readline'); -const stripAnsi = require('strip-ansi'); -const { spawn } = require('child_process'); const acorn = require('acorn-loose'); -const chalk = require('chalk'); const { Session } = require('./inspector'); const { isIdentifier, strEscape, underlineIgnoreANSI } = require('./util'); const highlight = require('./highlight'); const getHistory = require('./history'); +const util = require('util'); + +require('./stub.js') + +function stripAnsi(text) { + const ansiEscape = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g; + return text.replace(ansiEscape, ''); +} function makePrompt(i) { - return chalk.green(`In [${chalk.bold(i)}]: `); + return util.styleText('green', `In [${util.styleText('bold', '' + i)}]: `); } function makePromptOut(inspected, i) { if (/[\r\n\u2028\u2029]/u.test(inspected)) { return ''; } - return chalk.red(`Out[${chalk.bold(i)}]: `); + return util.styleText('red', `Out[${util.styleText('bold', '' + i)}]: `); } function promptLength(i) { return `In [${i}]: `.length; } -async function start(wsUrl) { - const session = await Session.create(wsUrl); +async function start() { + const session = await Session.create(); + + const { context } = await new Promise((resolve) => { + session.once('Runtime.executionContextCreated', resolve); + session.post('Runtime.enable'); + }); - session.post('Runtime.enable'); - const [{ context }] = await Session.once(session, 'Runtime.executionContextCreated'); const { result: remoteGlobal } = await session.post('Runtime.evaluate', { expression: 'globalThis', }); @@ -113,8 +121,8 @@ async function start(wsUrl) { // Convert inspection target to object. if (evaluateResult.result.type !== 'object' - && evaluateResult.result.type !== 'undefined' - && evaluateResult.result.subtype !== 'null') { + && evaluateResult.result.type !== 'undefined' + && evaluateResult.result.subtype !== 'null') { evaluateResult = await evaluate(`Object(${expr})`, true); if (evaluateResult.exceptionDetails) { return undefined; @@ -205,19 +213,28 @@ async function start(wsUrl) { } return callFunctionOn( `function inspect(v) { - const i = util.inspect(v, { + let i = util.inspect(v, { colors: false, breakLength: Infinity, compact: true, maxArrayLength: 10, depth: 1, }); - return i.split('\\n')[0].trim(); + return i; }`, [result], ); }) - .then(({ result }) => result.value) + .then(({ result }) => { + let val = result.value; + let noAnsi = stripAnsi(val); + let length = process.stdout.columns - promptLength(promptIndex) - 2; + if (noAnsi.length > length) { + noAnsi = noAnsi.slice(0, length - 3) + '...'; + } + + return noAnsi; + }) .catch(() => undefined); const rl = createInterface({ @@ -371,10 +388,8 @@ async function start(wsUrl) { process.stdout.cursorTo(promptLength(promptIndex) + rl.cursor); if (inspectedLine !== '') { - Promise.all([ - completeLine(inspectedLine), - getPreview(inspectedLine), - ]) + completeLine(inspectedLine) + .then(async(completion) => [completion, await getPreview(inspectedLine + (completion?.completions[0] || ''))]) .then(([completion, preview]) => { if (rl.line !== inspectedLine) { return; @@ -386,18 +401,18 @@ async function start(wsUrl) { ([completionCache] = completion.completions); } process.stdout.cursorTo(promptLength(promptIndex) + rl.line.length); - process.stdout.write(chalk.grey(completion.completions[0])); + process.stdout.write(util.styleText('grey', completion.completions[0])); rows += countLines(completion.completions[0]) - 1; } if (preview) { - process.stdout.write(chalk.grey(`\nOut[${promptIndex}]: ${preview}\n`)); + process.stdout.write(util.styleText('grey', `\nOut[${promptIndex}]: ${preview}\n`)); rows += countLines(preview) + 1; } process.stdout.cursorTo(promptLength(promptIndex) + rl.cursor); process.stdout.moveCursor(0, -rows); }) - .catch(() => {}); + .catch(() => { }); } }; @@ -420,7 +435,6 @@ Prototype REPL - https://github.com/nodejs/repl 'function inspect(uncaught, line, value) { return globalThis[Symbol.for("nodejs.repl.updateInspect")](uncaught, line, value); }', [{ value: uncaught }, { value: promptIndex }, result], ); - process.stdout.write(`${makePromptOut(inspected.value, promptIndex)}${uncaught ? 'Uncaught ' : ''}${inspected.value}\n\n`); promptIndex += 1; @@ -438,25 +452,4 @@ Prototype REPL - https://github.com/nodejs/repl } } -const child = spawn(process.execPath, [ - '--inspect-publish-uid=http', - ...process.execArgv, - require.resolve('./stub.js'), - ...process.argv, -], { - cwd: process.cwd(), - windowsHide: true, -}); - -child.stdout.on('data', (data) => { - process.stdout.write(data); -}); - -child.stderr.on('data', (data) => { - const s = data.toString(); - if (s.startsWith('__DEBUGGER_URL__')) { - start(s.split(' ')[1]); - } else if (s !== 'Debugger attached.\n') { - process.stderr.write(data); - } -}); +start(); \ No newline at end of file diff --git a/src/inspector.js b/src/inspector.js index 59bc62e..25f300b 100644 --- a/src/inspector.js +++ b/src/inspector.js @@ -1,59 +1,70 @@ 'use strict'; const { EventEmitter } = require('events'); -const WebSocket = require('ws'); +const inspector = require('inspector'); + +const events = [ + 'inspectorNotification', + 'Runtime.executionContextCreated', + 'Runtime.executionContextDestroyed', + 'Runtime.executionContextsCleared', + 'Runtime.exceptionThrown', + 'Runtime.exceptionRevoked', + 'Runtime.consoleAPICalled', + 'Runtime.inspectRequested', + 'Debugger.scriptParsed', + 'Debugger.scriptFailedToParse', + 'Debugger.breakpointResolved', + 'Debugger.paused', + 'Debugger.resumed', + 'Console.messageAdded', + 'Profiler.consoleProfileStarted', + 'Profiler.consoleProfileFinished', + 'HeapProfiler.addHeapSnapshotChunk', + 'HeapProfiler.resetProfiles', + 'HeapProfiler.reportHeapSnapshotProgress', + 'HeapProfiler.lastSeenObjectId', + 'HeapProfiler.heapStatsUpdate', + 'NodeTracing.dataCollected', + 'NodeTracing.tracingComplete', + 'NodeWorker.attachedToWorker', + 'NodeWorker.detachedFromWorker', + 'NodeWorker.receivedMessageFromWorker', + 'NodeRuntime.waitingForDisconnect' +]; class Session extends EventEmitter { constructor(url) { super(); - this.ws = new WebSocket(url); - this.ws.on('message', (d) => { - this.onMessage(d); - }); - this.ws.on('open', () => { - this.emit('open'); - }); + this.session = new inspector.Session(); + this.session.connect(); - this.messageCounter = 0; - this.messages = new Map(); + for (const event of events) { + this.session.on(event, this.onMessage.bind(this)); + } } static create(url) { - return new Promise((resolve) => { - const s = new Session(url); - s.once('open', () => resolve(s)); - }); + return new Session(url); } onMessage(d) { - const { id, method, params, result, error } = JSON.parse(d); + const { method, params } = d; if (method) { this.emit(method, params); - } else { - const { resolve, reject } = this.messages.get(id); - this.messages.delete(id); - if (error) { - const e = new Error(error.message); - e.code = error.code; - reject(e); - } else { - resolve(result); - } } } post(method, params) { return new Promise((resolve, reject) => { - const id = this.messageCounter; - this.messageCounter += 1; - const message = { - method, - params, - id, - }; - this.messages.set(id, { resolve, reject }); - this.ws.send(JSON.stringify(message)); + this.session.post(method, params, (err, result) => { + if (err) { + reject(err); + } else { + resolve(result); + } + }); }); } } diff --git a/src/stub.js b/src/stub.js index a7c8866..d7be274 100644 --- a/src/stub.js +++ b/src/stub.js @@ -2,17 +2,8 @@ const Module = require('module'); const path = require('path'); -const inspector = require('inspector'); const util = require('util'); -inspector.open(0, true); -process.stderr.write(`__DEBUGGER_URL__ ${inspector.url()}`); - -if (process.platform !== 'win32') { - util.inspect.styles.number = 'blue'; - util.inspect.styles.bigint = 'blue'; -} - Module.builtinModules .filter((x) => !/^_|\//.test(x)) .forEach((name) => { @@ -97,7 +88,4 @@ globalThis[Symbol.for('nodejs.repl.updateInspect')] = (uncaught, line, value) => colors: true, showProxy: true, }); -}; - -// keep process alive using stdin -process.stdin.on('data', () => {}); +}; \ No newline at end of file