Skip to content
File

Blob: src/workerd/api/node/exceptions.c++

3.8 KB
1#include "exceptions.h"
2 
3namespace workerd::api::node {
4 
5namespace {
6jsg::JsObject createJsError(jsg::Lock& js, JsErrorType type, kj::StringPtr message) {
7 switch (type) {
8 case JsErrorType::TypeError: {
9 return KJ_ASSERT_NONNULL(js.typeError(message).tryCast<jsg::JsObject>());
10 }
11 case JsErrorType::RangeError: {
12 return KJ_ASSERT_NONNULL(js.rangeError(message).tryCast<jsg::JsObject>());
13 }
14 case JsErrorType::Error: {
15 KJ_FALLTHROUGH;
16 }
17 default: {
18 return KJ_ASSERT_NONNULL(js.error(message).tryCast<jsg::JsObject>());
19 }
20 }
21 KJ_UNREACHABLE;
22}
23 
24constexpr kj::StringPtr getMessage(NodeExceptionCode code, kj::StringPtr message) {
25 if (message != nullptr) return message;
26 switch (code) {
27 case NodeExceptionCode::ERR_FS_CP_EEXIST:
28 return "File already exists";
29 case NodeExceptionCode::ERR_FS_CP_DIR_TO_NON_DIR:
30 return "Cannot copy directory to non-directory";
31 case NodeExceptionCode::ERR_FS_CP_EINVAL:
32 return "Invalid cp operation";
33 case NodeExceptionCode::ERR_FS_CP_NON_DIR_TO_DIR:
34 return "Cannot copy non-directory to directory";
35 case NodeExceptionCode::ERR_FS_EISDIR:
36 return "Expected a file but found a directory";
37 default:
38 return "Unknown Node.js exception";
39 }
40}
41 
42constexpr kj::StringPtr getCode(NodeExceptionCode code) {
43#define V(name) \
44 case NodeExceptionCode::name: \
45 return #name;
46 switch (code) {
47 NODE_EXCEPTION_CODE_LIST(V)
48 default:
49 return "UNKNOWN";
50 }
51#undef V
52}
53} // namespace
54 
55jsg::JsValue createNodeException(
56 jsg::Lock& js, NodeExceptionCode code, JsErrorType type, kj::StringPtr message) {
57 auto err = createJsError(js, type, getMessage(code, message));
58 err.set(js, "code"_kj, js.str(getCode(code)));
59 return err;
60}
61 
62namespace {
63// Generates the error name.
64#define UV_ERR_NAME_GEN(name, _) \
65 case UV_##name: \
66 return js.str(#name##_kj);
67jsg::JsValue uv_err_name(jsg::Lock& js, int err) {
68 switch (err) { UV_ERRNO_MAP(UV_ERR_NAME_GEN) }
69 return js.str("UNKNOWN"_kj);
70}
71#undef UV_ERR_NAME_GEN
72} // namespace
73 
74jsg::JsValue createUVException(jsg::Lock& js,
75 int errorno,
76 kj::StringPtr syscall,
77 kj::StringPtr message,
78 kj::StringPtr path,
79 kj::StringPtr dest) {
80 KJ_DASSERT(syscall != nullptr, "syscall must not be null");
81 
82 // Format the message to match Node.js format: "ENOENT: no such file or directory, open 'path'"
83 kj::String formattedMessage;
84 if (message == nullptr) {
85 // Get the default error message
86 kj::String defaultMsg;
87 switch (errorno) {
88#define UV_MSG_GEN(name, msg) \
89 case UV_##name: \
90 defaultMsg = kj::str(msg); \
91 break;
92 UV_ERRNO_MAP(UV_MSG_GEN)
93#undef UV_MSG_GEN
94 default:
95 defaultMsg = kj::str("unknown error: ", errorno);
96 break;
97 }
98 
99 if (path != nullptr) {
100 formattedMessage = kj::str(defaultMsg, ", ", syscall, " '", path, "'");
101 } else {
102 formattedMessage = kj::mv(defaultMsg);
103 }
104 } else {
105 formattedMessage = kj::str(message);
106 }
107 
108 jsg::JsObject obj = KJ_ASSERT_NONNULL(js.error(formattedMessage).tryCast<jsg::JsObject>());
109 obj.set(js, "syscall"_kj, js.str(syscall));
110 obj.set(js, "code"_kj, uv_err_name(js, errorno));
111 
112 if (path != nullptr) {
113 obj.set(js, "path"_kj, js.str(path));
114 }
115 if (dest != nullptr) {
116 obj.set(js, "dest"_kj, js.str(dest));
117 }
118 
119 return obj;
120}
121 
122} // namespace workerd::api::node