Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: add error formatting support #37598

Merged
merged 1 commit into from
Mar 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -2323,6 +2323,11 @@ than the parent module. Linked modules must share the same context.

The linker function returned a module for which linking has failed.

<a id="ERR_VM_MODULE_LINK_FAILURE"></a>
### `ERR_VM_MODULE_LINK_FAILURE`

The module was unable to be linked due to a failure.

<a id="ERR_VM_MODULE_NOT_MODULE"></a>
### `ERR_VM_MODULE_NOT_MODULE`

Expand Down
2 changes: 2 additions & 0 deletions lib/internal/vm/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,8 @@ class SourceTextModule extends Module {
throw new ERR_VM_MODULE_DIFFERENT_CONTEXT();
}
if (module.status === 'errored') {
// TODO(devsnek): replace with ERR_VM_MODULE_LINK_FAILURE
// and error cause proposal.
throw new ERR_VM_MODULE_LINKING_ERRORED();
}
if (module.status === 'unlinked') {
Expand Down
24 changes: 14 additions & 10 deletions src/module_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,9 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
Local<Value> resolve_return_value =
maybe_resolve_return_value.ToLocalChecked();
if (!resolve_return_value->IsPromise()) {
env->ThrowError("linking error, expected resolver to return a promise");
THROW_ERR_VM_MODULE_LINK_FAILURE(
env, "request for '%s' did not return promise", specifier_std);
return;
}
Local<Promise> resolve_promise = resolve_return_value.As<Promise>();
obj->resolve_cache_[specifier_std].Reset(env->isolate(), resolve_promise);
Expand Down Expand Up @@ -497,33 +499,35 @@ MaybeLocal<Module> ModuleWrap::ResolveModuleCallback(

Isolate* isolate = env->isolate();

Utf8Value specifier_utf8(isolate, specifier);
std::string specifier_std(*specifier_utf8, specifier_utf8.length());

ModuleWrap* dependent = GetFromModule(env, referrer);
if (dependent == nullptr) {
env->ThrowError("linking error, null dep");
THROW_ERR_VM_MODULE_LINK_FAILURE(
env, "request for '%s' is from invalid module", specifier_std);
return MaybeLocal<Module>();
}

Utf8Value specifier_utf8(isolate, specifier);
std::string specifier_std(*specifier_utf8, specifier_utf8.length());

if (dependent->resolve_cache_.count(specifier_std) != 1) {
env->ThrowError("linking error, not in local cache");
THROW_ERR_VM_MODULE_LINK_FAILURE(
env, "request for '%s' is not in cache", specifier_std);
return MaybeLocal<Module>();
}

Local<Promise> resolve_promise =
dependent->resolve_cache_[specifier_std].Get(isolate);

if (resolve_promise->State() != Promise::kFulfilled) {
env->ThrowError("linking error, dependency promises must be resolved on "
"instantiate");
THROW_ERR_VM_MODULE_LINK_FAILURE(
env, "request for '%s' is not yet fulfilled", specifier_std);
return MaybeLocal<Module>();
}

Local<Object> module_object = resolve_promise->Result().As<Object>();
if (module_object.IsEmpty() || !module_object->IsObject()) {
env->ThrowError("linking error, expected a valid module object from "
"resolver");
THROW_ERR_VM_MODULE_LINK_FAILURE(
env, "request for '%s' did not return an object", specifier_std);
return MaybeLocal<Module>();
}

Expand Down
50 changes: 31 additions & 19 deletions src/node_errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "debug_utils-inl.h"
#include "env.h"
#include "v8.h"

Expand Down Expand Up @@ -75,29 +76,40 @@ void OnFatalError(const char* location, const char* message);
V(ERR_TLS_INVALID_PROTOCOL_METHOD, TypeError) \
V(ERR_TLS_PSK_SET_IDENTIY_HINT_FAILED, Error) \
V(ERR_VM_MODULE_CACHED_DATA_REJECTED, Error) \
V(ERR_VM_MODULE_LINK_FAILURE, Error) \
V(ERR_WASI_NOT_STARTED, Error) \
V(ERR_WORKER_INIT_FAILED, Error) \
V(ERR_PROTO_ACCESS, Error) \
V(ERR_PROTO_ACCESS, Error)

#define V(code, type) \
inline v8::Local<v8::Value> code(v8::Isolate* isolate, \
const char* message) { \
v8::Local<v8::String> js_code = OneByteString(isolate, #code); \
v8::Local<v8::String> js_msg = OneByteString(isolate, message); \
v8::Local<v8::Object> e = \
v8::Exception::type(js_msg)->ToObject( \
isolate->GetCurrentContext()).ToLocalChecked(); \
e->Set(isolate->GetCurrentContext(), OneByteString(isolate, "code"), \
js_code).Check(); \
return e; \
} \
inline void THROW_ ## code(v8::Isolate* isolate, const char* message) { \
isolate->ThrowException(code(isolate, message)); \
} \
inline void THROW_ ## code(Environment* env, const char* message) { \
THROW_ ## code(env->isolate(), message); \
#define V(code, type) \
template <typename... Args> \
inline v8::Local<v8::Value> code( \
v8::Isolate* isolate, const char* format, Args&&... args) { \
std::string message = SPrintF(format, std::forward<Args>(args)...); \
v8::Local<v8::String> js_code = OneByteString(isolate, #code); \
v8::Local<v8::String> js_msg = \
OneByteString(isolate, message.c_str(), message.length()); \
v8::Local<v8::Object> e = v8::Exception::type(js_msg) \
->ToObject(isolate->GetCurrentContext()) \
.ToLocalChecked(); \
e->Set(isolate->GetCurrentContext(), \
OneByteString(isolate, "code"), \
js_code) \
.Check(); \
return e; \
} \
template <typename... Args> \
inline void THROW_##code( \
v8::Isolate* isolate, const char* format, Args&&... args) { \
isolate->ThrowException( \
code(isolate, format, std::forward<Args>(args)...)); \
} \
template <typename... Args> \
inline void THROW_##code( \
Environment* env, const char* format, Args&&... args) { \
THROW_##code(env->isolate(), format, std::forward<Args>(args)...); \
}
ERRORS_WITH_CODE(V)
ERRORS_WITH_CODE(V)
#undef V

// Errors with predefined static messages
Expand Down