mirror of
https://github.com/oven-sh/bun
synced 2026-02-11 11:29:02 +00:00
Replace `catch bun.outOfMemory()`, which can accidentally catch non-OOM-related errors, with either `bun.handleOom` or a manual `catch |err| switch (err)`. (For internal tracking: fixes STAB-1070) --------- Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
183 lines
5.6 KiB
TypeScript
183 lines
5.6 KiB
TypeScript
import path from "node:path";
|
|
import NodeErrors from "../bun.js/bindings/ErrorCode.ts";
|
|
import { writeIfNotChanged } from "./helpers.ts";
|
|
const outputDir = process.argv[2];
|
|
|
|
if (!outputDir) {
|
|
throw new Error("Missing output directory");
|
|
}
|
|
|
|
const extra_count = NodeErrors.map(x => x.slice(3))
|
|
.filter(x => x.length > 0)
|
|
.reduce((ac, cv) => ac + cv.length, 0);
|
|
const count = NodeErrors.length + extra_count;
|
|
|
|
if (count > 1 << 16) {
|
|
// increase size of the enums below to have more tags
|
|
throw new Error(`NodeError can't fit ${count} codes in a u16`);
|
|
}
|
|
|
|
let enumHeader = ``;
|
|
let listHeader = ``;
|
|
let zig = ``;
|
|
|
|
enumHeader = `
|
|
// clang-format off
|
|
// Generated by: src/codegen/generate-node-errors.ts
|
|
// Input: src/bun.js/bindings/ErrorCode.ts
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
|
|
namespace Bun {
|
|
static constexpr size_t NODE_ERROR_COUNT = ${count};
|
|
enum class ErrorCode : uint16_t {
|
|
`;
|
|
|
|
listHeader = `
|
|
// clang-format off
|
|
// Generated by: src/codegen/generate-node-errors.ts
|
|
#pragma once
|
|
|
|
#include <JavaScriptCore/ErrorType.h>
|
|
|
|
struct ErrorCodeData {
|
|
JSC::ErrorType type;
|
|
WTF::ASCIILiteral name;
|
|
WTF::ASCIILiteral code;
|
|
};
|
|
static constexpr ErrorCodeData errors[${count}] = {
|
|
`;
|
|
|
|
zig = `
|
|
// Generated by: src/codegen/generate-node-errors.ts
|
|
const std = @import("std");
|
|
const bun = @import("bun");
|
|
const jsc = bun.jsc;
|
|
|
|
pub fn ErrorBuilder(comptime code: Error, comptime fmt: [:0]const u8, Args: type) type {
|
|
return struct {
|
|
global: *jsc.JSGlobalObject,
|
|
args: Args,
|
|
|
|
// Throw this error as a JS exception
|
|
pub inline fn throw(this: @This()) bun.JSError {
|
|
return code.throw(this.global, fmt, this.args);
|
|
}
|
|
|
|
/// Turn this into a JSValue
|
|
pub inline fn toJS(this: @This()) jsc.JSValue {
|
|
return code.fmt(this.global, fmt, this.args);
|
|
}
|
|
|
|
/// Turn this into a JSPromise that is already rejected.
|
|
pub inline fn reject(this: @This()) jsc.JSValue {
|
|
if (comptime bun.FeatureFlags.breaking_changes_1_3) {
|
|
return jsc.JSPromise.rejectedPromise(this.globalThis, code.fmt(this.global, fmt, this.args)).toJS();
|
|
} else {
|
|
return jsc.JSPromise.dangerouslyCreateRejectedPromiseValueWithoutNotifyingVM(this.global, code.fmt(this.global, fmt, this.args));
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const Error = enum(u16) {
|
|
|
|
`;
|
|
|
|
let i = 0;
|
|
for (let [code, constructor, name, ...other_constructors] of NodeErrors) {
|
|
if (name == null) name = constructor.name;
|
|
|
|
// it's useful to avoid the prefix, but module not found has a prefixed and unprefixed version
|
|
const codeWithoutPrefix = code === "ERR_MODULE_NOT_FOUND" ? code : code.replace(/^ERR_/, "");
|
|
|
|
enumHeader += ` ${code} = ${i},\n`;
|
|
listHeader += ` { JSC::ErrorType::${constructor.name}, "${name}"_s, "${code}"_s },\n`;
|
|
zig += ` /// ${name}: ${code} (instanceof ${constructor.name})\n`;
|
|
zig += ` ${codeWithoutPrefix} = ${i},\n`;
|
|
i++;
|
|
|
|
for (const con of other_constructors) {
|
|
if (con == null) continue;
|
|
if (name == null) name = con.name;
|
|
enumHeader += ` ${code}_${con.name} = ${i},\n`;
|
|
listHeader += ` { JSC::ErrorType::${con.name}, "${con.name}"_s, "${code}"_s },\n`;
|
|
zig += ` /// ${name}: ${code} (instanceof ${con.name})\n`;
|
|
zig += ` ${codeWithoutPrefix}_${con.name} = ${i},\n`;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
enumHeader += `
|
|
};
|
|
} // namespace Bun
|
|
`;
|
|
|
|
listHeader += `
|
|
};
|
|
`;
|
|
|
|
zig += `
|
|
|
|
|
|
extern fn Bun__createErrorWithCode(globalThis: *jsc.JSGlobalObject, code: Error, message: *bun.String) jsc.JSValue;
|
|
|
|
/// Creates an Error object with the given error code.
|
|
/// If an error is thrown while creating the Error object, returns that error instead.
|
|
/// Derefs the message string.
|
|
pub fn toJS(this: Error, globalThis: *jsc.JSGlobalObject, message: *bun.String) jsc.JSValue {
|
|
defer message.deref();
|
|
return Bun__createErrorWithCode(globalThis, this, message);
|
|
}
|
|
|
|
pub fn fmt(this: Error, globalThis: *jsc.JSGlobalObject, comptime fmt_str: [:0]const u8, args: anytype) jsc.JSValue {
|
|
if (comptime std.meta.fieldNames(@TypeOf(args)).len == 0) {
|
|
var message = bun.String.static(fmt_str);
|
|
return toJS(this, globalThis, &message);
|
|
}
|
|
|
|
var message = bun.handleOom(bun.String.createFormat(fmt_str, args));
|
|
return toJS(this, globalThis, &message);
|
|
}
|
|
|
|
pub fn throw(this: Error, globalThis: *jsc.JSGlobalObject, comptime fmt_str: [:0]const u8, args: anytype) bun.JSError {
|
|
return globalThis.throwValue(fmt(this, globalThis, fmt_str, args));
|
|
}
|
|
|
|
};
|
|
`;
|
|
|
|
let builtindtsPath = path.join(import.meta.dir, "..", "..", "src", "js", "builtins.d.ts");
|
|
let builtindts = await Bun.file(builtindtsPath).text();
|
|
|
|
let dts = `
|
|
// Generated by: src/codegen/generate-node-errors.ts
|
|
// Input: src/bun.js/bindings/ErrorCode.ts
|
|
|
|
// Global error code functions for TypeScript
|
|
`;
|
|
for (const [code, constructor, name, ...other_constructors] of NodeErrors) {
|
|
const hasExistingOverride = builtindts.includes(`declare function $${code}`);
|
|
if (hasExistingOverride) {
|
|
continue;
|
|
}
|
|
|
|
const namedError =
|
|
name && name !== constructor.name
|
|
? `${constructor.name} & { name: "${name}", code: "${code}" }`
|
|
: `${constructor.name} & { code: "${code}" }`;
|
|
dts += `
|
|
/**
|
|
* Construct an {@link ${constructor.name} ${constructor.name}} with the \`"${code}"\` error code.
|
|
*
|
|
* To override this, update ErrorCode.cpp. To remove this generated type, mention \`"${code}"\` in builtins.d.ts.
|
|
*/
|
|
declare function $${code}(message: string): ${namedError};\n`;
|
|
}
|
|
|
|
writeIfNotChanged(path.join(outputDir, "ErrorCode+List.h"), enumHeader);
|
|
writeIfNotChanged(path.join(outputDir, "ErrorCode+Data.h"), listHeader);
|
|
writeIfNotChanged(path.join(outputDir, "ErrorCode.zig"), zig);
|
|
writeIfNotChanged(path.join(outputDir, "ErrorCode.d.ts"), dts);
|