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 1.1.0 to 1.2.0

.eslintignore

2

.eslintrc.json

@@ -73,3 +73,3 @@ {

"@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }],
"@typescript-eslint/no-empty-function": ["error", { "allow": ["overrideMethods"] }],
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/restrict-template-expressions": ["error", {

@@ -76,0 +76,0 @@ "allowNumber": true,

{
"type": "module",
"name": "bun-repl",
"version": "1.1.0",
"version": "1.2.0",
"description": "Experimental unofficial REPL for Bun",

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

@@ -13,6 +13,16 @@ # bun-repl [![GitHub version][github-image]][github-url] [![GitHub code size in bytes][size-image]][github-url] [![license][license-image]][license-url]

## Features
* Seamless JavaScript & TypeScript execution
* Single run CLI flags `--eval` and `--print`
* Top level import syntax supported (`import fs from 'fs'`)
* Import either CommonJS or ESM local files and packages into the REPL
* Node.js REPL special underscore variables provided (`_` and `_error`)
* Resistent to global object modification (output quality may decrease but never crash)
* Node.js `repl` module polyfill
* Execution history (`↑` `↓`)
* REPL Commands (`.command`)
## Usage
```sh
bun run repl -- [options]
# or
bun-repl [options]

@@ -26,14 +36,21 @@ ```

## Features
### The `repl` module polyfill
`bun-repl` exposes a special variable `repl` which provides access to a REPL interface like the Node.js REPL (also accessible through import/require of `repl` or `node:repl`).
* Seamless JavaScript & TypeScript execution
* Top level import syntax supported (`import fs from 'fs'`)
* Import either CommonJS or ESM local files and packages into the REPL
* Node.js REPL special underscore variables provided (`_` and `_error`)
* Node.js `repl` module polyfill
* Execution history (`↑` `↓`)
* REPL Commands (`.command`)
Currently only a subset of the `node:repl` API is implemented, see below:
* `repl` global object ✅
* `start()` function ❌
* `writer()` function ✅
* `options` object ✅
* `repl` property ❌
* `builtinModules` array ✅
* `REPL_MODE_SLOPPY` symbol ✅
* `REPL_MODE_STRICT` symbol ✅
* `REPLServer` class ❌
* `Recoverable` class ❌
You can use `repl.writer.options` like you would in Node.js REPL to customize the live output of the running REPL.
## Known issues & limitations
Please keep in mind this is unofficial and experimental software built on top of experimental software, there **ARE** bugs. Additionally, Bun will obviously be getting an official native REPL in the future which certainly will be much better, this module is merely serving as a temporary alternative until then.
Please keep in mind this is unofficial and experimental software built on top of experimental software (Bun). Additionally, Bun will obviously be getting an official native REPL in the future which certainly will be much better, this module is merely serving as a temporary alternative until then.

@@ -40,0 +57,0 @@ PRs are welcome to help fix any of the items below or anything else.

@@ -0,2 +1,8 @@

import repl from './module/repl';
type globalType = typeof globalThis;
declare global {
const globalThis: globalType;
interface ShadowRealm {

@@ -67,2 +73,20 @@ /**

function require(moduleIdentifier: string): unknown;
interface REPLGlobal {
REPL: typeof repl;
global: typeof globalThis;
eval: typeof eval;
temp: Record<any, any>;
process: Process;
format: (v: any, isError?: boolean) => [string, null] | [null, Error]
console: typeof console;
Error: ErrorConstructor;
Symbol: SymbolConstructor;
StringReplace: Primordial<string, (find: string | RegExp, value: string) => string>;
StringSlice: Primordial<string, typeof String.prototype.slice>;
ArrayIncludes: Primordial<Array<any>, typeof Array.prototype.includes>;
ObjectToString: Primordial<any, typeof Object.prototype.toString>;
}
type Primordial<T, F extends (...x: any[]) => any> = (thisArg: T, ...args: Parameters<F>) => ReturnType<F>;
}

@@ -69,0 +93,0 @@

/* eslint-disable unicorn/custom-error-definition */
// Polyfill of the Node.js "repl" module (WIP)
import $ from '../colors';
import bun from 'bun';
import { SafeInspect } from '../utils';
import utl from '../utl';
class NotImplementedError extends Error {
constructor(method: string) {
super(method + ' is not implemented');
constructor(method: string, fullmsg: boolean = false) {
super(fullmsg ? method : method + ' is not implemented');
this.name = 'NotImplementedError';

@@ -16,86 +14,79 @@ }

export const nodePrefixedModules = [
'assert', 'buffer', 'constants', 'crypto', 'domain', 'events',
'fs', 'fs/promises', 'http', 'https', 'os', 'path', 'path/posix',
'path/win32', 'process', 'punycode', 'querystring', 'stream',
'string_decoder', 'sys', 'timers', 'tty', 'url', 'util', 'zlib'
'assert', 'buffer', 'console', 'constants', 'crypto', 'domain', 'events',
'fs', 'fs/promises', 'http', 'https', 'module', 'net', 'os', 'path',
'path/posix', 'path/win32', 'perf_hooks', 'process', 'punycode',
'querystring', 'stream', 'streams/consumer', 'streams/web', 'string_decoder',
'sys', 'timers', 'timers/promises', 'tty', 'url', 'util', 'zlib'
];
export const bunPrefixedModules = ['ffi', 'jsc', 'sqlite', 'test'];
export const bunPrefixedModules = ['ffi', 'jsc', 'sqlite', 'wrap'];
export const unprefixedModules = [
'@vercel/fetch', 'depd', 'detect-libc', 'isomorphic-fetch', 'node-fetch', 'supports-color', 'undici', 'ws'
];
export const builtinModules = [
...bunPrefixedModules.map(m => `bun:${m}`),
...nodePrefixedModules.map(m => `node:${m}`),
...unprefixedModules
] as const;
module repl {
export const repl = new Error('bun-repl does not run on a REPLServer');
export class REPLServer {
constructor() {
throw new NotImplementedError('repl.REPLServer');
}
export class REPLServer {
constructor() {
throw new NotImplementedError('repl.REPLServer');
}
}
export class Recoverable extends SyntaxError {
err: Error;
constructor(err: Error) {
super();
this.err = err;
throw new NotImplementedError('repl.Recoverable');
}
export class Recoverable extends SyntaxError {
readonly err: Error;
constructor(err: Error) {
super();
this.err = err;
throw new NotImplementedError('repl.Recoverable');
}
}
/** `bun` and `bun:test` are excluded as they can't be dynamically imported. */
export const builtinModules = [
...bunPrefixedModules.map(m => `bun:${m}`),
...nodePrefixedModules.map(m => `node:${m}`),
'supports-color'
];
export const REPL_MODE_SLOPPY = Symbol('repl-sloppy');
export const REPL_MODE_STRICT = Symbol('repl-strict');
export const REPL_MODE_SLOPPY = Symbol('repl-sloppy');
export const REPL_MODE_STRICT = Symbol('repl-strict');
export function start(prompt: string, source: any, eval_: any, useGlobal: boolean, ignoreUndefined: boolean, replMode: symbol) {
//return new REPLServer(prompt, source, eval_, useGlobal, ignoreUndefined, replMode);
throw new NotImplementedError('repl.start');
}
export function start(prompt: string, source: any, eval_: any, useGlobal: boolean, ignoreUndefined: boolean, replMode: symbol) {
//return new REPLServer(prompt, source, eval_, useGlobal, ignoreUndefined, replMode);
throw new NotImplementedError('repl.start');
}
interface REPLWriterFunction {
(val: any): string;
options: utl.InspectOptions;
}
const REPLWriterOptionsDefaults = {
showHidden: false,
depth: 2,
colors: bun.enableANSIColors,
customInspect: true,
showProxy: true,
maxArrayLength: 100,
maxStringLength: 10000,
breakLength: 80,
compact: 3,
sorted: false,
getters: false,
numericSeparator: false
};
interface REPLWriterFunction {
(val: any): string;
options: typeof REPLWriterOptionsDefaults;
}
export const writer = function writer(val: any): string {
const REPLGlobal = Reflect.get((async function*(){}).constructor, '@@REPLGlobal') as REPLGlobal;
const [formatted, err] = REPLGlobal.format(val);
if (err) throw err;
else return formatted;
} as REPLWriterFunction;
Object.defineProperty(writer, 'options', {
value: { ...utl.inspect.replDefaults }, enumerable: true
});
export const writer = function writer(val: any): string {
return (SafeInspect(val, (<REPLWriterFunction>writer).options) ?? bun.inspect(val));
} as REPLWriterFunction;
Object.defineProperty(writer, 'options', {
value: new Proxy(REPLWriterOptionsDefaults, {
set(target, p, value) {
console.warn(`${$.yellow+$.dim}(warning) repl.writer.options are currently not all fully respected by the REPL.${$.reset}`);
// @ts-expect-error Temporary warning Proxy
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
target[p] = value;
return true;
}
}), enumerable: true
});
}
const repl = Object.defineProperties({}, {
start: { value: start, enumerable: true },
writer: { value: writer, enumerable: true },
repl: {
get() { throw new NotImplementedError('bun-repl does not run on a REPLServer', true); },
enumerable: true
},
builtinModules: { value: builtinModules, enumerable: true },
REPL_MODE_SLOPPY: { value: REPL_MODE_SLOPPY, enumerable: true },
REPL_MODE_STRICT: { value: REPL_MODE_STRICT, enumerable: true },
REPLServer: { value: REPLServer, enumerable: true },
Recoverable: { value: Recoverable, enumerable: true }
}) as {
start: typeof start,
writer: typeof writer,
repl: REPLServer,
builtinModules: typeof builtinModules,
REPL_MODE_SLOPPY: typeof REPL_MODE_SLOPPY,
REPL_MODE_STRICT: typeof REPL_MODE_STRICT,
REPLServer: typeof REPLServer,
Recoverable: typeof Recoverable
};
// For verifying all builtin modules
/*for (const mod of repl.builtinModules) {
if (mod === 'bun' || mod === 'bun:test') continue;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const contents = await import(mod);
if (!contents) throw new Error(`Module does not exist: ${mod}`);
}*/
export default repl;

@@ -125,7 +125,7 @@ #!/usr/bin/env bun

try {
const evalIn = util.inspect(transpiled);
const evalIn = util.inspect(transpiled); // Inspect for appropriate string quotes selection
realm.evaluate(`//'use strict'; (Strict mode currently causes issues that need fixing)
let $__SHADOWREALM_EVAL_RETURN_VALUE__ = [];
try {
$__SHADOWREALM_EVAL_RETURN_VALUE__[0] = (async function*() {}).constructor['@@REPLGlobal'].eval(${evalIn});
$__SHADOWREALM_EVAL_RETURN_VALUE__[0] = (async function*(){}).constructor['@@REPLGlobal'].eval(${evalIn});
} catch (error) {

@@ -165,4 +165,5 @@ $__SHADOWREALM_EVAL_RETURN_VALUE__[0] = _error = error;

Environment variables:
BUN_REPL_PROMPT A string to override the default "> " prompt with.
BUN_REPL_MODE Either "sloppy" or "strict" (Not implemented)`);
BUN_REPL_HISTORY_SIZE The maximum number of lines to store in the history. (Default: 1000)
BUN_REPL_PROMPT A string to override the default REPL prompt with. (Default: "> ")
BUN_REPL_MODE Either "sloppy" or "strict". (Default: "strict") [Not Implemented]`);
}

@@ -181,3 +182,3 @@

Installed at: ${$.cyan+path.join(import.meta.dir, '..')+$.reset}
Bun version: ${process.version}
Bun version: ${process.version}${process.revision ? `-${process.revision}` : ''}
SWC version: v${swc.version as string}

@@ -184,0 +185,0 @@ Color mode: ${$.bool(Bun.enableANSIColors)}

import $ from './colors';
import fs from 'fs';
import os from 'os';
import readline from 'rustybun';

@@ -9,7 +10,13 @@

this.prompt = process.env.BUN_REPL_PROMPT ?? prompt;
historyPath ||= `${process.env.BUN_INSTALL ?? '~'}/.bun_repl_history`;
historyPath ||= `${process.env.BUN_INSTALL ?? os.homedir()}/.bun_repl_history`;
const historyLines = fs.readFileSync(historyPath, 'utf8').split('\n');
const maxHistoryLines = Number(process.env.BUN_REPL_HISTORY_SIZE ?? 1000) || 1000;
if (historyLines.length > maxHistoryLines) {
fs.writeFileSync(historyPath, historyLines.slice(historyLines.length - maxHistoryLines).join('\n'));
}
this.loadHistory(historyPath);
this.#historyfd = fs.openSync(historyPath, 'a+');
this.#historypath = historyPath;
}

@@ -16,0 +23,0 @@

@@ -31,3 +31,3 @@ import swc from '@swc/core';

globals: { vars: {
repl: '(async function*() {}).constructor["@@REPLGlobal"].REPL'
repl: '(async function*(){}).constructor["@@REPLGlobal"].REPL'
} }

@@ -34,0 +34,0 @@ }

@@ -47,2 +47,4 @@ import swc from '@swc/core';

($0, varname: string) => 'var ' + varname)
.replace(/(?:let|const) ?({[A-Za-z_$, \t\n\d]+?}) ?(=.)/g,
($0, vars: string, end: string) => `var ${vars} ${end}`)
.replace(/var (_.+?) = require\("(.+?)"\);[ \t\n;]*\/\*\$replTranspiledImport:({.+?})\*\//g,

@@ -49,0 +51,0 @@ ($0, requireVar: string, requireStr: string, infoStr: string) => {

/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/restrict-plus-operands */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import bun from 'bun';
import $ from './colors';
import utl from './utl';
import util from 'util';
/**
* Safely get an object's property.
* If an error occurs, just treat it as non-existent.
* Convert the input prototype method into a primordial function.
*
* This is not REPL-runtime safe, it should only be called during initial setup.
*/
export function SafeGet(obj: any, key: string | number | symbol): any {
try {
return obj?.[key];
} catch {
return; // undefined
}
export function Primordial<T, F extends (...x: any[]) => any>(fn: F): Primordial<T, F> {
return Function.prototype.call.bind(fn);
}
/**
* Safely call a function on an object as the `this`.
* Safely get an object's property.
* If an error occurs, just treat it as non-existent.
*/
export function SafeThiscall<F extends (...x: any[]) => any>(fn: F, thisArg: any, ...args: Parameters<F>): ReturnType<F> | undefined {
export function SafeGet(obj: any, key: string | number | symbol): any {
try {
return fn?.apply?.(thisArg, args);
return obj?.[key];
} catch {

@@ -31,11 +32,41 @@ return; // undefined

/**
* Safely call util.inspect.
* If an error occurs, simply return undefined.
* Safely inspect a value, falling down through implementations as they fail.
* If all inspectors fail, simply return undefined.
* @param bunInspectReturnsValue Should all inspectors before `Bun.inspect` fail,
* if this is set to true, `SafeInspect` will return the input value as is, and
* expect the caller to know how to handle this scenario and pass the value
* along to console.log or other custom fallback methods for the value.
*/
export function SafeInspect(val: any, opts?: util.InspectOptions): string | undefined {
export function SafeInspect(val: any, opts: util.InspectOptions = {}, bunInspectReturnsValue: boolean = false): string {
try {
return util.inspect(val, opts);
try {
return utl.inspect(val, opts);
} catch {
//void 0; throw err;
try {
return util.inspect(val, opts);
} catch {
// Bun's native inspect is expected to never fail
// Unfortunately it doesn't print colors nor inspect
// certain values very accurately, nor does it support
// the options object, therefore it's the last to run for now.
return bunInspectReturnsValue ? val : bun.inspect(val);
}
}
} catch {
return;
//void 0; throw err2;
try {
// In the greatly unexpected event of Bun's native inspect failing,
// panic back to the primitive method of string coercion.
console.warn($.yellow+$.dim+'All value inspection methods failed, this should not happen!'+$.reset);
const str = val + '';
// If the coercion somehow fails to return a proper string, resort to an empty one.
return typeof str === 'string' ? str : '';
} catch {
// Here's a fun fact about javascript.
// You can't rely even on string concatenation as a fully reliable string coercion method.
// Introducing, null prototype objects: `Object.create(null) + ""` = throws TypeError
return ''; // If this line of code ever runs, something truly catastrophic happened...
}
}
}

Sorry, the diff of this file is not supported yet

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