mirror of
https://github.com/denoland/deno.git
synced 2025-09-26 12:19:12 +00:00
fix(core): error registration could pollute constructors (#10422)
Co-authored-by: Luca Casonato <lucacasonato@yahoo.com>
This commit is contained in:
parent
7bc03523d0
commit
d21380728f
4 changed files with 85 additions and 15 deletions
31
core/core.js
31
core/core.js
|
@ -6,15 +6,15 @@
|
||||||
const { opcall } = window.Deno.core;
|
const { opcall } = window.Deno.core;
|
||||||
|
|
||||||
let opsCache = {};
|
let opsCache = {};
|
||||||
const errorMap = {
|
const errorMap = {};
|
||||||
// Builtin v8 / JS errors
|
// Builtin v8 / JS errors
|
||||||
Error,
|
registerErrorClass("Error", Error);
|
||||||
RangeError,
|
registerErrorClass("RangeError", RangeError);
|
||||||
ReferenceError,
|
registerErrorClass("ReferenceError", ReferenceError);
|
||||||
SyntaxError,
|
registerErrorClass("SyntaxError", SyntaxError);
|
||||||
TypeError,
|
registerErrorClass("TypeError", TypeError);
|
||||||
URIError,
|
registerErrorClass("URIError", URIError);
|
||||||
};
|
|
||||||
let nextPromiseId = 1;
|
let nextPromiseId = 1;
|
||||||
const promiseMap = new Map();
|
const promiseMap = new Map();
|
||||||
const RING_SIZE = 4 * 1024;
|
const RING_SIZE = 4 * 1024;
|
||||||
|
@ -83,23 +83,27 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerErrorClass(className, errorClass) {
|
function registerErrorClass(className, errorClass) {
|
||||||
|
registerErrorBuilder(className, (msg) => new errorClass(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerErrorBuilder(className, errorBuilder) {
|
||||||
if (typeof errorMap[className] !== "undefined") {
|
if (typeof errorMap[className] !== "undefined") {
|
||||||
throw new TypeError(`Error class for "${className}" already registered`);
|
throw new TypeError(`Error class for "${className}" already registered`);
|
||||||
}
|
}
|
||||||
errorMap[className] = errorClass;
|
errorMap[className] = errorBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
function unwrapOpResult(res) {
|
function unwrapOpResult(res) {
|
||||||
// .$err_class_name is a special key that should only exist on errors
|
// .$err_class_name is a special key that should only exist on errors
|
||||||
if (res?.$err_class_name) {
|
if (res?.$err_class_name) {
|
||||||
const className = res.$err_class_name;
|
const className = res.$err_class_name;
|
||||||
const ErrorClass = errorMap[className];
|
const errorBuilder = errorMap[className];
|
||||||
if (!ErrorClass) {
|
if (!errorBuilder) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unregistered error class: "${className}"\n ${res.message}\n Classes of errors returned from ops should be registered via Deno.core.registerErrorClass().`,
|
`Unregistered error class: "${className}"\n ${res.message}\n Classes of errors returned from ops should be registered via Deno.core.registerErrorClass().`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
throw new ErrorClass(res.message);
|
throw errorBuilder(res.message);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -138,6 +142,7 @@
|
||||||
close,
|
close,
|
||||||
print,
|
print,
|
||||||
resources,
|
resources,
|
||||||
|
registerErrorBuilder,
|
||||||
registerErrorClass,
|
registerErrorClass,
|
||||||
handleAsyncMsgFromRust,
|
handleAsyncMsgFromRust,
|
||||||
syncOpsCache,
|
syncOpsCache,
|
||||||
|
|
30
core/error_builder_test.js
Normal file
30
core/error_builder_test.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
const { core } = Deno;
|
||||||
|
|
||||||
|
class DOMException {
|
||||||
|
constructor(message, code) {
|
||||||
|
this.msg = message;
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core.registerErrorBuilder(
|
||||||
|
"DOMExceptionOperationError",
|
||||||
|
function DOMExceptionOperationError(msg) {
|
||||||
|
return new DOMException(msg, "OperationError");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
core.opSync("op_err", undefined, null);
|
||||||
|
throw new Error("op_err didn't throw!");
|
||||||
|
} catch (err) {
|
||||||
|
if (!(err instanceof DOMException)) {
|
||||||
|
throw new Error("err not DOMException");
|
||||||
|
}
|
||||||
|
if (err.msg !== "abc") {
|
||||||
|
throw new Error("err.message is incorrect");
|
||||||
|
}
|
||||||
|
if (err.code !== "OperationError") {
|
||||||
|
throw new Error("err.code is incorrect");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1521,7 +1521,9 @@ impl JsRuntime {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::error::custom_error;
|
||||||
use crate::modules::ModuleSourceFuture;
|
use crate::modules::ModuleSourceFuture;
|
||||||
|
use crate::op_sync;
|
||||||
use futures::future::lazy;
|
use futures::future::lazy;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -1768,6 +1770,39 @@ pub mod tests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_error_builder() {
|
||||||
|
fn op_err(
|
||||||
|
_: &mut OpState,
|
||||||
|
_: (),
|
||||||
|
_: Option<ZeroCopyBuf>,
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
|
Err(custom_error("DOMExceptionOperationError", "abc"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_error_class_name(_: &AnyError) -> &'static str {
|
||||||
|
"DOMExceptionOperationError"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_in_task(|mut cx| {
|
||||||
|
let mut runtime = JsRuntime::new(RuntimeOptions {
|
||||||
|
get_error_class_fn: Some(&get_error_class_name),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
runtime.register_op("op_err", op_sync(op_err));
|
||||||
|
runtime.sync_ops_cache();
|
||||||
|
runtime
|
||||||
|
.execute(
|
||||||
|
"error_builder_test.js",
|
||||||
|
include_str!("error_builder_test.js"),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
if let Poll::Ready(Err(_)) = runtime.poll_event_loop(&mut cx) {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn will_snapshot() {
|
fn will_snapshot() {
|
||||||
let snapshot = {
|
let snapshot = {
|
||||||
|
|
|
@ -184,10 +184,10 @@ delete Object.prototype.__proto__;
|
||||||
core.registerErrorClass("Http", errors.Http);
|
core.registerErrorClass("Http", errors.Http);
|
||||||
core.registerErrorClass("Busy", errors.Busy);
|
core.registerErrorClass("Busy", errors.Busy);
|
||||||
core.registerErrorClass("NotSupported", errors.NotSupported);
|
core.registerErrorClass("NotSupported", errors.NotSupported);
|
||||||
core.registerErrorClass(
|
core.registerErrorBuilder(
|
||||||
"DOMExceptionOperationError",
|
"DOMExceptionOperationError",
|
||||||
function DOMExceptionOperationError(msg) {
|
function DOMExceptionOperationError(msg) {
|
||||||
DOMException.prototype.constructor.call(this, msg, "OperationError");
|
return new DOMException(msg, "OperationError");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue