Compare commits

...

3 Commits

Author SHA1 Message Date
dave caruso
f47277988f ok 2024-12-10 14:39:30 -08:00
dave caruso
ac75182fcd extract readline internals 2024-12-10 14:38:52 -08:00
dave caruso
eccf42a2e4 allow importing internals when --expose-internals 2024-12-10 14:29:39 -08:00
10 changed files with 113 additions and 156 deletions

32
.vscode/launch.json generated vendored
View File

@@ -62,22 +62,6 @@
// Don't pause when the GC runs while the debugger is open.
"postRunCommands": ["process handle -p true -s false -n false SIGUSR1"],
},
{
"type": "lldb",
"request": "launch",
"name": "bun test [file] (verbose)",
"program": "${workspaceFolder}/build/debug/bun-debug",
"args": ["test", "${file}"],
"cwd": "${workspaceFolder}",
"env": {
"BUN_DEBUG_QUIET_LOGS": "0",
"BUN_DEBUG_jest": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
},
"console": "internalConsole",
// Don't pause when the GC runs while the debugger is open.
"postRunCommands": ["process handle -p true -s false -n false SIGUSR1"],
},
{
"type": "lldb",
"request": "launch",
@@ -205,6 +189,22 @@
// Don't pause when the GC runs while the debugger is open.
"postRunCommands": ["process handle -p true -s false -n false SIGUSR1"],
},
{
"type": "lldb",
"request": "launch",
"name": "bun --expose-internals run [file]",
"program": "${workspaceFolder}/build/debug/bun-debug",
"args": ["--expose-internals", "run", "${file}"],
"cwd": "${workspaceFolder}",
"env": {
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_DEBUG_jest": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "0",
},
"console": "internalConsole",
// Don't pause when the GC runs while the debugger is open.
"postRunCommands": ["process handle -p true -s false -n false SIGUSR1"],
},
{
"type": "lldb",
"request": "launch",

View File

@@ -2564,6 +2564,12 @@ pub const VirtualMachine = struct {
} else {
return error.ModuleNotFound;
}
} else if (ModuleLoader.is_allowed_to_use_internal_testing_apis or Environment.isDebug) {
if (JSC.internal_modules.get(specifier) != null) {
ret.result = null;
ret.path = specifier;
return;
}
}
const is_special_source = strings.eqlComptime(source, main_file_name) or js_ast.Macro.isMacroPath(source);

View File

@@ -88,7 +88,7 @@ const String = bun.String;
const debug = Output.scoped(.ModuleLoader, true);
inline fn jsSyntheticModule(comptime name: ResolvedSource.Tag, specifier: String) ResolvedSource {
inline fn jsSyntheticModule(name: ResolvedSource.Tag, specifier: String) ResolvedSource {
return ResolvedSource{
.allocator = null,
.source_code = bun.String.empty,
@@ -222,7 +222,7 @@ pub const RuntimeTranspilerStore = struct {
};
}
// Thsi is run at the top of the event loop on the JS thread.
// This is run at the top of the event loop on the JS thread.
pub fn drain(this: *RuntimeTranspilerStore) void {
var batch = this.queue.popBatch();
var iter = batch.iterator();
@@ -2462,15 +2462,6 @@ pub const ModuleLoader = struct {
return jsSyntheticModule(.InternalForTesting, specifier);
},
.@"internal/test/binding" => {
if (!Environment.isDebug) {
if (!is_allowed_to_use_internal_testing_apis)
return null;
}
return jsSyntheticModule(.@"internal:test/binding", specifier);
},
// These are defined in src/js/*
.@"bun:ffi" => return jsSyntheticModule(.@"bun:ffi", specifier),
.@"bun:sql" => {
@@ -2584,6 +2575,10 @@ pub const ModuleLoader = struct {
.is_commonjs_module = file.module_format == .cjs,
};
}
} else if (is_allowed_to_use_internal_testing_apis or Environment.isDebug) {
if (internal_modules.getWithEql(specifier, bun.String.eqlComptime)) |tag| {
return jsSyntheticModule(tag, specifier);
}
}
return null;
@@ -2675,6 +2670,23 @@ pub const FetchFlags = enum {
const SavedSourceMap = JSC.SavedSourceMap;
pub const internal_modules = brk: {
const all_modules = std.enums.values(ResolvedSource.Tag);
var internal_module_entries: std.BoundedArray(
struct { []const u8, ResolvedSource.Tag },
all_modules.len,
) = .{};
for (all_modules) |module| {
if (std.mem.startsWith(u8, @tagName(module), "internal:")) {
internal_module_entries.appendAssumeCapacity(.{
"internal/" ++ @tagName(module)["internal:".len..],
module,
});
}
}
break :brk bun.ComptimeStringMap(ResolvedSource.Tag, internal_module_entries.slice());
};
pub const HardcodedModule = enum {
bun,
@"abort-controller",
@@ -2746,7 +2758,6 @@ pub const HardcodedModule = enum {
@"node:cluster",
// these are gated behind '--expose-internals'
@"bun:internal-for-testing",
@"internal/test/binding",
/// Already resolved modules go in here.
/// This does not remap the module name, it is just a hash table.
@@ -2826,8 +2837,6 @@ pub const HardcodedModule = enum {
.{ "@vercel/fetch", HardcodedModule.@"@vercel/fetch" },
.{ "utf-8-validate", HardcodedModule.@"utf-8-validate" },
.{ "abort-controller", HardcodedModule.@"abort-controller" },
.{ "internal/test/binding", HardcodedModule.@"internal/test/binding" },
},
);

View File

@@ -1,5 +1,5 @@
// TODO: Use native code and JSC intrinsics for everything in this file.
// Do not use this file for new code, many things here will be slow especailly when intrinsics for these operations is available.
// Do not use this file for new code, many things here will be slow especially when intrinsics for these operations is available.
// It is primarily used for `internal/util`
const createSafeIterator = (factory, next) => {

View File

@@ -0,0 +1,58 @@
const { validateString } = require("internal/validators");
const StringPrototypeNormalize = String.prototype.normalize;
const RegExpPrototypeSymbolReplace = RegExp.prototype[Symbol.replace];
const internalGetStringWidth = $newZigFunction("string.zig", "String.jsGetStringWidth", 1);
const kEscape = "\x1b";
/**
* Returns the number of columns required to display the given string.
*/
var getStringWidth = function getStringWidth(str, removeControlChars = true) {
if (removeControlChars) str = stripVTControlCharacters(str);
str = StringPrototypeNormalize.$call(str, "NFC");
return internalGetStringWidth(str);
};
// Regex used for ansi escape code splitting
// Adopted from https://github.com/chalk/ansi-regex/blob/HEAD/index.js
// License: MIT, authors: @sindresorhus, Qix-, arjunmehta and LitoMore
// Matches all ansi escape code sequences in a string
var ansiPattern =
"[\\u001B\\u009B][[\\]()#;?]*" +
"(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*" +
"|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)" +
"|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))";
var ansi = new RegExp(ansiPattern, "g");
/**
* Remove all VT control characters. Use to estimate displayed string width.
*/
function stripVTControlCharacters(str) {
validateString(str, "str");
return RegExpPrototypeSymbolReplace.$call(ansi, str, "");
}
function CSI(strings, ...args) {
var ret = `${kEscape}[`;
for (var n = 0; n < strings.length; n++) {
ret += strings[n];
if (n < args.length) ret += args[n];
}
return ret;
}
CSI.kEscape = kEscape;
CSI.kClearLine = CSI`2K`;
CSI.kClearScreenDown = CSI`0J`;
CSI.kClearToLineBeginning = CSI`1K`;
CSI.kClearToLineEnd = CSI`0K`;
const utils = {
getStringWidth,
stripVTControlCharacters,
};
export default { CSI, utils };

View File

@@ -1,3 +1,5 @@
process.emitWarning("These APIs are for internal testing only. Do not use them.", "internal/test/binding");
function internalBinding(name: string) {
switch (name) {
case "async_wrap":

View File

@@ -27,6 +27,8 @@
// ----------------------------------------------------------------------------
const EventEmitter = require("node:events");
const { StringDecoder } = require("node:string_decoder");
const { CSI, utils: { getStringWidth, stripVTControlCharacters } } = require("internal/readline/utils");
const { kClearLine, kClearScreenDown, kClearToLineBeginning, kClearToLineEnd } = CSI;
const {
validateFunction,
@@ -38,7 +40,6 @@ const {
validateUint32,
} = require("internal/validators");
const internalGetStringWidth = $newZigFunction("string.zig", "String.jsGetStringWidth", 1);
const ObjectGetPrototypeOf = Object.getPrototypeOf;
const ObjectGetOwnPropertyDescriptors = Object.getOwnPropertyDescriptors;
@@ -72,7 +73,6 @@ const ArrayPrototypeReverse = Array.prototype.reverse;
const ArrayPrototypeShift = Array.prototype.shift;
const ArrayPrototypeUnshift = Array.prototype.unshift;
const RegExpPrototypeExec = RegExp.prototype.exec;
const RegExpPrototypeSymbolReplace = RegExp.prototype[SymbolReplace];
const StringFromCharCode = String.fromCharCode;
const StringPrototypeCharCodeAt = String.prototype.charCodeAt;
const StringPrototypeCodePointAt = String.prototype.codePointAt;
@@ -130,34 +130,6 @@ var SafeStringIterator = createSafeIterator(StringPrototypeSymbolIterator, Strin
// Section: "Internal" modules
// ----------------------------------------------------------------------------
/**
* Returns the number of columns required to display the given string.
*/
var getStringWidth = function getStringWidth(str, removeControlChars = true) {
if (removeControlChars) str = stripVTControlCharacters(str);
str = StringPrototypeNormalize.$call(str, "NFC");
return internalGetStringWidth(str);
};
// Regex used for ansi escape code splitting
// Adopted from https://github.com/chalk/ansi-regex/blob/HEAD/index.js
// License: MIT, authors: @sindresorhus, Qix-, arjunmehta and LitoMore
// Matches all ansi escape code sequences in a string
var ansiPattern =
"[\\u001B\\u009B][[\\]()#;?]*" +
"(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*" +
"|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)" +
"|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))";
var ansi = new RegExp(ansiPattern, "g");
/**
* Remove all VT control characters. Use to estimate displayed string width.
*/
function stripVTControlCharacters(str) {
validateString(str, "str");
return RegExpPrototypeSymbolReplace.$call(ansi, str, "");
}
// Promisify
var kCustomPromisifiedSymbol = SymbolFor("nodejs.util.promisify.custom");
@@ -314,23 +286,6 @@ class AbortError extends Error {
// Section: Utils
// ----------------------------------------------------------------------------
function CSI(strings, ...args) {
var ret = `${kEscape}[`;
for (var n = 0; n < strings.length; n++) {
ret += strings[n];
if (n < args.length) ret += args[n];
}
return ret;
}
var kClearLine, kClearScreenDown, kClearToLineBeginning, kClearToLineEnd;
CSI.kEscape = kEscape;
CSI.kClearLine = kClearLine = CSI`2K`;
CSI.kClearScreenDown = kClearScreenDown = CSI`0J`;
CSI.kClearToLineBeginning = kClearToLineBeginning = CSI`1K`;
CSI.kClearToLineEnd = kClearToLineEnd = CSI`0K`;
function charLengthLeft(str: string, i: number) {
if (i <= 0) return 0;
if (
@@ -2937,12 +2892,4 @@ export default {
return new PromisesInterface(input, output, completer, terminal);
},
},
[SymbolFor("__BUN_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED__")]: {
CSI,
utils: {
getStringWidth,
stripVTControlCharacters,
},
},
};

View File

@@ -1,9 +1,7 @@
import readline from "node:readline";
var {
// Flags: --expose-internals
const {
utils: { getStringWidth },
// @ts-ignore
} = readline[Symbol.for("__BUN_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED__")];
} = require("internal/readline/utils");
it("handles invisible ASCII character at any position", () => {
const visible = "a";

View File

@@ -4,12 +4,10 @@ import { EventEmitter } from "node:events";
import readline from "node:readline";
import { PassThrough, Writable } from "node:stream";
const { beforeEach, describe, it, createDoneDotAll, createCallCheckCtx, assert } = createTest(import.meta.path);
var {
const {
CSI,
utils: { getStringWidth, stripVTControlCharacters },
// @ts-ignore
} = readline[Symbol.for("__BUN_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED__")];
} = require("internal/readline/utils");
// ----------------------------------------------------------------------------
// Helpers

View File

@@ -1,61 +0,0 @@
import path from "path";
import fs from "fs";
import { spawn } from "child_process";
const localDir = path.resolve(import.meta.dirname, "./parallel");
const upstreamDir = path.resolve(import.meta.dirname, "../../../node.js/upstream/test/parallel");
const localFiles = fs.readdirSync(localDir);
const upstreamFiles = fs.readdirSync(upstreamDir);
const newFiles = upstreamFiles.filter((file) => !localFiles.includes(file));
process.on('SIGTERM', () => {
console.log("SIGTERM received");
});
process.on('SIGINT', () => {
console.log("SIGINT received");
});
const stdin = process.stdin;
if (stdin.isTTY) {
stdin.setRawMode(true);
stdin.on('data', (data) => {
if (data[0] === 0x03) {
stdin.setRawMode(false);
console.log("Cancelled");
process.exit(0);
}
});
}
process.on('exit', () => {
if (stdin.isTTY) {
stdin.setRawMode(false);
}
});
for (const file of newFiles) {
await new Promise<void>((resolve, reject) => {
// Run with a timeout of 5 seconds
const proc = spawn("bun-debug", ["run", path.join(upstreamDir, file)], {
timeout: 5000,
stdio: "inherit",
env: {
...process.env,
BUN_DEBUG_QUIET_LOGS: "1",
},
});
proc.on("error", (err) => {
console.error(err);
});
proc.on("exit", (code) => {
if (code === 0) {
console.log(`New Pass: ${file}`);
fs.appendFileSync("new-passes.txt", file + "\n");
}
resolve();
});
});
}