New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

bun-repl

Package Overview
Dependencies
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bun-repl - npm Package Compare versions

Comparing version 2.0.5 to 2.0.6

2

package.json
{
"type": "module",
"name": "bun-repl",
"version": "2.0.5",
"version": "2.0.6",
"description": "Experimental REPL for Bun",

@@ -6,0 +6,0 @@ "main": "src/module/repl.ts",

@@ -23,3 +23,3 @@ #!/usr/bin/env bun

const validFlags = [
'-h', '--help', '-e', '--eval', '-p', '--print', '--debug', '--sloppy'
'-h', '--help', '-e', '--eval', '-p', '--print', '--debug', '--sloppy', '--no-history',
] as const;

@@ -26,0 +26,0 @@ if (process.argv.length > 2) {

import { type JSC } from 'bun-devtools';
import { join, dirname, basename, resolve as pathresolve } from 'node:path';
import { readFileSync, existsSync, readSync } from 'node:fs';
import os from 'node:os';

@@ -10,3 +11,3 @@ import readline from 'node:readline';

import utl, { $Proxy } from './utl';
import bun, { serve, inspect as bunInspect } from 'bun';
import bun, { serve, write, inspect as bunInspect } from 'bun';
const { exit, cwd } = process;

@@ -53,7 +54,14 @@

const { isBuffer } = Buffer;
const SymbolToStringTag = Symbol.toStringTag;
const JSONParse = JSON.parse;
const JSONStringify = JSON.stringify;
const ObjectAssign = Object.assign;
const ObjectDefineProperty = Object.defineProperty;
const ReflectGet = Reflect.get;
const ReflectSet = Reflect.set;
const ReflectDeleteProperty = Reflect.deleteProperty;
const FunctionApply = Function.prototype.call.bind(Function.prototype.apply) as Primordial<Function, 'apply'>;
const BufferToString = Function.prototype.call.bind(Reflect.get(Buffer.prototype, 'toString') as Buffer['toString']) as Primordial<Buffer, 'toString'>;
const StringTrim = Function.prototype.call.bind(String.prototype.trim) as Primordial<String, 'trim'>;
const StringPrototypeSlice = Function.prototype.call.bind(String.prototype.slice) as Primordial<String, 'slice'>;
const StringPrototypeSplit = Function.prototype.call.bind(String.prototype.split) as Primordial<String, 'split'>;

@@ -65,2 +73,4 @@ const StringPrototypeIncludes = Function.prototype.call.bind(String.prototype.includes) as Primordial<String, 'includes'>;

const ArrayPrototypeJoin = Function.prototype.call.bind(Array.prototype.join) as Primordial<Array<any>, 'join'>;
const ArrayPrototypeFind = Function.prototype.call.bind(Array.prototype.find) as Primordial<Array<any>, 'find'>;
const ArrayPrototypeFilter = Function.prototype.call.bind(Array.prototype.filter) as Primordial<Array<any>, 'filter'>;
const MapGet = Function.prototype.call.bind(Map.prototype.get) as Primordial<Map<any, any>, 'get'>;

@@ -80,5 +90,8 @@ const MapSet = Function.prototype.call.bind(Map.prototype.set) as Primordial<Map<any, any>, 'set'>;

};
// Uncomment below for extreme debugging
//for (const k in console) console[k as keyof typeof console] = GLOBAL.console.trace;
const IS_DEBUG = process.argv.includes('--debug');
const debuglog = IS_DEBUG ? (...args: string[]) => (console.debug($.dim+'DEBUG:', ...args, $.reset)) : () => void 0;
//const SLOPPY_MODE = process.argv.includes('--sloppy');
const NO_HISTORY = process.env.BUN_REPL_NO_HISTORY || process.argv.includes('--no-history');

@@ -256,2 +269,51 @@ type Primordial<T, M extends keyof T> = <S extends T>(

}
// Yes, if someone types a 0xFFFF characters line, they will fill up the buffer.
// But that's very unlikely to happen, and if it does, it will just cutoff the line.
// Anyway this just a temporary workaround for https://github.com/oven-sh/bun/issues/5267
const promptReuseBuffer = Buffer.allocUnsafe(0xFFFF);
const stdoutWrite = process.stdout.write.bind(process.stdout);
globalThis.prompt = function prompt(question: string = 'Prompt', defaultValue: unknown = null): string | null {
stdoutWrite(question + ' ');
let i = -1;
// eslint-disable-next-line no-constant-condition
while (true) {
// This currently relies on https://github.com/oven-sh/bun/issues/5305
// If that bug is fixed, this will break one way or another.
const read = readSync(0, promptReuseBuffer, { length: 1, offset: ++i });
if (read !== 1) {
if (read === 0) { // This means the buffer got filled up (unlikely, but possible)
stdoutWrite('\n');
return BufferToString(promptReuseBuffer, 'utf8', 0, i) || defaultValue as string | null;
}
else throw new Error('Unexpected read length'); // This will tell us if the bug is fixed.
}
const char = promptReuseBuffer[i];
if (char === 3) {
stdoutWrite('^C\n');
exit(0);
}
if (char === 4) {
stdoutWrite('\n');
return defaultValue as string | null;
}
if (char === 27) {
stdoutWrite('^[');
continue;
}
if (char === 127) {
i--;
if (i < 0) continue;
stdoutWrite('\b \b');
if (promptReuseBuffer[i] === 27) stdoutWrite('\b \b');
i--;
continue;
}
stdoutWrite(BufferToString(promptReuseBuffer, 'utf8', i, i + 1));
if (char === 13 || char === 10) {
stdoutWrite('\n');
return BufferToString(promptReuseBuffer, 'utf8', 0, i) || defaultValue as string | null;
}
}
};
Object.defineProperty(GLOBAL, '@@bunReplRuntimeHelpers', {

@@ -266,2 +328,4 @@ value: Object.freeze({

Object.defineProperty(GLOBAL, 'eval', { value: eval, configurable: false, writable: false }); // used by inlined import.meta trick
Object.defineProperty(GLOBAL, 'Object', { value: Object, configurable: false, writable: false }); // used by swc
Object.freeze(Object); // bun's node:events polyfill relies on this
Object.freeze(Promise); // must preserve .name property

@@ -277,4 +341,4 @@ // eslint-disable-next-line @typescript-eslint/no-floating-promises

const thiz = this;
function* wrappedIter() { yield* original.apply(thiz, argz); }
return Object.defineProperty(wrappedIter(), Symbol.toStringTag, { value: name, configurable: true });
function* wrappedIter() { yield* FunctionApply(original, thiz, argz) as Generator; }
return ObjectDefineProperty(wrappedIter(), SymbolToStringTag, { value: name, configurable: true });
});

@@ -332,3 +396,3 @@ };

async eval(code: string, topLevelAwaited = false, extraOut?: { errored?: boolean, noPrintError?: boolean }): Promise<string> {
debuglog(`transpiled code: ${code.trimEnd()}`);
debuglog(`transpiled code: ${StringTrim(code)}`);
const { result, wasThrown: thrown } = await this.rawEval(code);

@@ -354,3 +418,3 @@ let remoteObj: EvalRemoteObject = result;

}
if (result.preview.properties?.find(p => p.name === 'status')?.value === 'rejected') {
if (result.preview.properties && ArrayPrototypeFind(result.preview.properties, p => p.name === 'status')?.value === 'rejected') {
remoteObj.wasRejectedPromise = true;

@@ -365,7 +429,7 @@ }

if (!remoteObj.description) throw new EvalError(`Received BigInt value without description: ${JSONStringify(remoteObj)}`);
const value = BigInt(remoteObj.description.slice(0, -1));
Reflect.set(GLOBAL, remoteObj.wasThrown ? '_error' : '_', value);
const value = BigInt(StringPrototypeSlice(remoteObj.description, 0, -1));
ReflectSet(GLOBAL, remoteObj.wasThrown ? '_error' : '_', value);
return (remoteObj.wasThrown ? $.red + 'Uncaught ' + $.reset : '') + SafeInspect(value,
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
Reflect.get(GLOBAL, 'repl')?.writer?.options as utl.InspectOptions
ReflectGet(GLOBAL, 'repl')?.writer?.options as utl.InspectOptions
?? { colors: Bun.enableANSIColors, showProxy: true }

@@ -377,4 +441,4 @@ );

const REPL_INTERNALS = '@@bunReplInternals';
Object.defineProperty(GLOBAL, REPL_INTERNALS, {
value: { SafeInspect, SafeGet, StringReplace },
ObjectDefineProperty(GLOBAL, REPL_INTERNALS, {
value: { SafeInspect, SafeGet, StringReplace, bunInspect },
configurable: true,

@@ -385,3 +449,3 @@ });

functionDeclaration: `(v) => {
const { SafeInspect, SafeGet, StringReplace } = this['${REPL_INTERNALS}'];
const { SafeInspect, SafeGet, StringReplace, bunInspect } = this['${REPL_INTERNALS}'];
if (!${wasThrown!}) this._ = v;

@@ -394,3 +458,3 @@ else this._error = v;

)}${$.reset}\`;
if (${remoteObj.subtype === 'error'}) return Bun.inspect(v, { colors: ${Bun.enableANSIColors} });
if (${remoteObj.subtype === 'error'}) return bunInspect(v, { colors: ${Bun.enableANSIColors} });
return SafeInspect(v, this.repl?.writer?.options ?? { colors: ${Bun.enableANSIColors}, showProxy: true });

@@ -400,3 +464,3 @@ }`,

});
Reflect.deleteProperty(GLOBAL, REPL_INTERNALS);
ReflectDeleteProperty(GLOBAL, REPL_INTERNALS);
if (inspected.wasThrown) throw new EvalError(`Failed to inspect object: ${JSONStringify(inspected)}`);

@@ -414,2 +478,3 @@ if (!this.typeof(inspected.result, 'string')) throw new EvalError(`Received non-string inspect result: ${JSONStringify(inspected)}`);

async function loadHistoryData(): Promise<{ path: string, lines: string[] }> {
if (NO_HISTORY) return { path: '', lines: [] };
let out: { path: string; lines: string[]; } | null;

@@ -428,10 +493,9 @@ if (process.env.XDG_DATA_HOME && (out = await tryLoadHistory(process.env.XDG_DATA_HOME, 'bun'))) return out;

debuglog(`Trying to load REPL history from ${path}`);
let file = Bun.file(path);
if (!await file.exists()) {
if (!existsSync(path)) {
debuglog(`History file not found, creating new one at ${path}`);
await Bun.write(path, '\n');
file = Bun.file(path); // BUG: Bun.file doesn't update the file's status after writing to it
await write(path, '\n');
// BUG: Bun.file doesn't update the file's status after writing to it
}
debuglog(`Loading history file from ${path}`);
return { path, lines: (await file.text()).split('\n') };
return { path, lines: readFileSync(path, 'utf8').split('\n') };
} catch (err) {

@@ -475,2 +539,8 @@ debuglog(`Failed to load history file from ${path}\nError will be printed below:`);

debuglog('Debug mode enabled.');
if (IS_DEBUG) { // while debuglog by itself is handy for simple strings its important to note JS will still evaluate the arguments
debuglog(
`REPL version ${await tryGetPackageVersion()} running on Bun v${Bun.version}+${Bun.revision} (${process.platform} ${process.arch})`
);
debuglog(`OS Info: ${os.type()} -- ${os.release()} -- ${os.version()}`);
}
const repl = new REPLServer();

@@ -524,3 +594,4 @@ await repl.ready;

}
debuglog(`REPL history data loaded: (${history.lines.length} lines) ${history.path}`);
if (NO_HISTORY) debuglog('Skipped history file loading due to --no-history flag.');
else debuglog(`REPL history data loaded: (${history.lines.length} lines) ${history.path}`);
const rl = readline.createInterface({

@@ -542,2 +613,5 @@ input: process.stdin,

debuglog('readline interface created.');
process.on('exit', () => {
rl.close();
});
console.log(`Welcome to Bun v${Bun.version}\nType ".help" for more information.`);

@@ -548,5 +622,15 @@ console.warn(

//* Only primordials should be used beyond this point!
rl.on('SIGINT', () => {
if (rl.line.length === 0) rl.close();
else {
console.log('');
ReflectSet(rl, 'line', '');
rl.prompt();
}
});
rl.on('close', () => {
Bun.write(history.path, history.lines.filter(l => l !== '.exit').join('\n'))
.catch(() => console.warn(`[!] Failed to save REPL history to ${history.path}!`));
if (!NO_HISTORY) write(
history.path,
ArrayPrototypeJoin(ArrayPrototypeFilter(history.lines, l => l !== '.exit'), '\n')
).catch(() => console.warn(`[!] Failed to save REPL history to ${history.path}!`));
console.log(''); // ensure newline

@@ -601,3 +685,15 @@ exit(0);

const err = e as Error;
console.error((err?.message ?? 'Unknown transpiler error.').split('\nCaused by:\n')[0].trim());
if (err.stack?.includes('@swc/core')) {
console.error(
'Internal failure due to global builtins tampering, this is not a bug but a temporary limitation of the REPL.\n' +
'Please do not report this and avoid tampering with the global builtins in the REPL.'
);
exit(0);
}
console.error(
StringTrim(StringPrototypeSplit(
err?.message ?? 'Unknown transpiler error.', '\nCaused by:\n' as unknown as RegExp
)[0])
);
if (IS_DEBUG) console.error(e);
rl.prompt();

@@ -604,0 +700,0 @@ return;

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc