mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-09 09:34:57 +09:00
LibJS: Update spec steps / links for the JSON modules proposal
This proposal has reached stage 4 and been merged into the main ECMA-262
spec. See:
3feb1ba
This commit is contained in:
parent
3867a192a1
commit
2401764697
Notes:
github-actions[bot]
2025-04-29 11:34:58 +00:00
Author: https://github.com/trflynn89
Commit: 2401764697
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4514
5 changed files with 191 additions and 130 deletions
|
@ -419,22 +419,57 @@ JS_DEFINE_NATIVE_FUNCTION(JSONObject::parse)
|
|||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
auto string = TRY(vm.argument(0).to_string(vm));
|
||||
auto text = vm.argument(0);
|
||||
auto reviver = vm.argument(1);
|
||||
|
||||
auto json = JsonValue::from_string(string);
|
||||
if (json.is_error())
|
||||
return vm.throw_completion<SyntaxError>(ErrorType::JsonMalformed);
|
||||
Value unfiltered = parse_json_value(vm, json.value());
|
||||
// 1. Let jsonString be ? ToString(text).
|
||||
auto json_string = TRY(text.to_string(vm));
|
||||
|
||||
// 2. Let unfiltered be ? ParseJSON(jsonString).
|
||||
auto unfiltered = TRY(parse_json(vm, json_string));
|
||||
|
||||
// 3. If IsCallable(reviver) is true, then
|
||||
if (reviver.is_function()) {
|
||||
// a. Let root be OrdinaryObjectCreate(%Object.prototype%).
|
||||
auto root = Object::create(realm, realm.intrinsics().object_prototype());
|
||||
auto root_name = String {};
|
||||
|
||||
// b. Let rootName be the empty String.
|
||||
String root_name;
|
||||
|
||||
// c. Perform ! CreateDataPropertyOrThrow(root, rootName, unfiltered).
|
||||
MUST(root->create_data_property_or_throw(root_name, unfiltered));
|
||||
|
||||
// d. Return ? InternalizeJSONProperty(root, rootName, reviver).
|
||||
return internalize_json_property(vm, root, root_name, reviver.as_function());
|
||||
}
|
||||
// 4. Else,
|
||||
// a. Return unfiltered.
|
||||
return unfiltered;
|
||||
}
|
||||
|
||||
// 25.5.1.1 ParseJSON ( text ), https://tc39.es/ecma262/#sec-ParseJSON
|
||||
ThrowCompletionOr<Value> JSONObject::parse_json(VM& vm, StringView text)
|
||||
{
|
||||
auto json = JsonValue::from_string(text);
|
||||
|
||||
// 1. If StringToCodePoints(text) is not a valid JSON text as specified in ECMA-404, throw a SyntaxError exception.
|
||||
if (json.is_error())
|
||||
return vm.throw_completion<SyntaxError>(ErrorType::JsonMalformed);
|
||||
|
||||
// 2. Let scriptString be the string-concatenation of "(", text, and ");".
|
||||
// 3. Let script be ParseText(scriptString, Script).
|
||||
// 4. NOTE: The early error rules defined in 13.2.5.1 have special handling for the above invocation of ParseText.
|
||||
// 5. Assert: script is a Parse Node.
|
||||
// 6. Let result be ! Evaluation of script.
|
||||
auto result = JSONObject::parse_json_value(vm, json.value());
|
||||
|
||||
// 7. NOTE: The PropertyDefinitionEvaluation semantics defined in 13.2.5.5 have special handling for the above evaluation.
|
||||
// 8. Assert: result is either a String, a Number, a Boolean, an Object that is defined by either an ArrayLiteral or an ObjectLiteral, or null.
|
||||
|
||||
// 9. Return result.
|
||||
return result;
|
||||
}
|
||||
|
||||
Value JSONObject::parse_json_value(VM& vm, JsonValue const& value)
|
||||
{
|
||||
if (value.is_object())
|
||||
|
@ -448,7 +483,7 @@ Value JSONObject::parse_json_value(VM& vm, JsonValue const& value)
|
|||
if (value.is_string())
|
||||
return PrimitiveString::create(vm, value.as_string());
|
||||
if (value.is_bool())
|
||||
return Value(static_cast<bool>(value.as_bool()));
|
||||
return Value(value.as_bool());
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
// test-js to communicate between the JS tests and the C++ test runner.
|
||||
static ThrowCompletionOr<Optional<String>> stringify_impl(VM&, Value value, Value replacer, Value space);
|
||||
|
||||
static ThrowCompletionOr<Value> parse_json(VM&, StringView text);
|
||||
static Value parse_json_value(VM&, JsonValue const&);
|
||||
|
||||
private:
|
||||
|
|
|
@ -525,10 +525,9 @@ VM::StoredModule* VM::get_stored_module(ImportedModuleReferrer const&, ByteStrin
|
|||
// FinishLoadingImportedModule(referrer, specifier, payload, result) where result is a normal completion,
|
||||
// then it must perform FinishLoadingImportedModule(referrer, specifier, payload, result) with the same result each time.
|
||||
|
||||
// Editor's Note from https://tc39.es/proposal-json-modules/#sec-hostresolveimportedmodule
|
||||
// The above text implies that is recommended but not required that hosts do not use moduleRequest.[[Assertions]]
|
||||
// as part of the module cache key. In either case, an exception thrown from an import with a given assertion list
|
||||
// does not rule out success of another import with the same specifier but a different assertion list.
|
||||
// Editor's Note from https://tc39.es/ecma262/#sec-hostresolveimportedmodule
|
||||
// The above text requires that hosts support JSON modules when imported with type: "json" (and HostLoadImportedModule
|
||||
// completes normally), but it does not prohibit hosts from supporting JSON modules when imported without type: "json".
|
||||
|
||||
// FIXME: This should probably check referrer as well.
|
||||
auto end_or_module = m_loaded_modules.find_if([&](StoredModule const& stored_module) {
|
||||
|
@ -612,6 +611,9 @@ void VM::load_imported_module(ImportedModuleReferrer referrer, ModuleRequest con
|
|||
// - If this operation is called multiple times with the same (referrer, specifier) pair and it performs
|
||||
// FinishLoadingImportedModule(referrer, specifier, payload, result) where result is a normal completion,
|
||||
// then it must perform FinishLoadingImportedModule(referrer, specifier, payload, result) with the same result each time.
|
||||
// - If moduleRequest.[[Attributes]] has an entry entry such that entry.[[Key]] is "type" and entry.[[Value]] is "json",
|
||||
// when the host environment performs FinishLoadingImportedModule(referrer, moduleRequest, payload, result), result
|
||||
// must either be the Completion Record returned by an invocation of ParseJSONModule or a throw completion.
|
||||
// - The operation must treat payload as an opaque value to be passed through to FinishLoadingImportedModule.
|
||||
//
|
||||
// The actual process performed is host-defined, but typically consists of performing whatever I/O operations are necessary to
|
||||
|
@ -680,10 +682,9 @@ void VM::load_imported_module(ImportedModuleReferrer referrer, ModuleRequest con
|
|||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] resolved {} + {} -> {}", base_path, module_request.module_specifier, filename);
|
||||
#endif
|
||||
|
||||
auto* loaded_module_or_end = get_stored_module(referrer, filename, module_type);
|
||||
if (loaded_module_or_end != nullptr) {
|
||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] load_imported_module({}) already loaded at {}", filename, loaded_module_or_end->module.ptr());
|
||||
finish_loading_imported_module(referrer, module_request, payload, *loaded_module_or_end->module);
|
||||
if (auto* loaded_module = get_stored_module(referrer, filename, module_type)) {
|
||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] load_imported_module({}) already loaded at {}", filename, loaded_module->module.ptr());
|
||||
finish_loading_imported_module(referrer, module_request, payload, *loaded_module->module);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -710,12 +711,13 @@ void VM::load_imported_module(ImportedModuleReferrer referrer, ModuleRequest con
|
|||
|
||||
StringView const content_view { file_content_or_error.value().bytes() };
|
||||
|
||||
auto module = [&]() -> ThrowCompletionOr<GC::Ref<Module>> {
|
||||
// If assertions has an entry entry such that entry.[[Key]] is "type", let type be entry.[[Value]]. The following requirements apply:
|
||||
// If type is "json", then this algorithm must either invoke ParseJSONModule and return the resulting Completion Record, or throw an exception.
|
||||
auto module = [&, content = file_content_or_error.release_value()]() -> ThrowCompletionOr<GC::Ref<Module>> {
|
||||
// If moduleRequest.[[Attributes]] has an entry entry such that entry.[[Key]] is "type" and entry.[[Value]] is "json",
|
||||
// when the host environment performs FinishLoadingImportedModule(referrer, moduleRequest, payload, result), result
|
||||
// must either be the Completion Record returned by an invocation of ParseJSONModule or a throw completion.
|
||||
if (module_type == "json"sv) {
|
||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] reading and parsing JSON module {}", filename);
|
||||
return parse_json_module(content_view, *current_realm(), filename);
|
||||
return parse_json_module(*current_realm(), content_view, filename);
|
||||
}
|
||||
|
||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] reading and parsing as SourceTextModule module {}", filename);
|
||||
|
@ -727,16 +729,17 @@ void VM::load_imported_module(ImportedModuleReferrer referrer, ModuleRequest con
|
|||
return throw_completion<SyntaxError>(module_or_errors.error().first().to_byte_string());
|
||||
}
|
||||
|
||||
auto module = module_or_errors.release_value();
|
||||
return module_or_errors.release_value();
|
||||
}();
|
||||
|
||||
if (!module.is_error()) {
|
||||
m_loaded_modules.empend(
|
||||
referrer,
|
||||
module->filename(),
|
||||
module.value()->filename(),
|
||||
String {}, // Null type
|
||||
make_root<Module>(*module),
|
||||
make_root(module.value()),
|
||||
true);
|
||||
|
||||
return module;
|
||||
}();
|
||||
}
|
||||
|
||||
finish_loading_imported_module(referrer, module_request, payload, module);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue