Browse Source

Add functions to create modules from a JSON value (#3804)

* Add functions to create modules from a JSON value

* Move json_module to Module::from_value_as_default

* Flag the whole json module behind the json feature

* Rename and add doc
pull/3812/head
Hans Larsen 9 months ago committed by GitHub
parent
commit
d915c9bef7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 37
      core/engine/src/module/mod.rs
  2. 65
      core/engine/tests/module.rs

37
core/engine/src/module/mod.rs

@ -29,6 +29,7 @@ use std::rc::Rc;
use rustc_hash::FxHashSet;
use boa_engine::js_string;
use boa_gc::{Finalize, Gc, GcRefCell, Trace};
use boa_interner::Interner;
use boa_parser::source::ReadChar;
@ -40,6 +41,7 @@ use source::SourceTextModule;
pub use synthetic::{SyntheticModule, SyntheticModuleInitializer};
use crate::{
builtins,
builtins::promise::{PromiseCapability, PromiseState},
environments::DeclarativeEnvironment,
object::{JsObject, JsPromise},
@ -204,6 +206,41 @@ impl Module {
}
}
/// Create a [`Module`] from a `JsValue`, exporting that value as the default export.
/// This will clone the module everytime it is initialized.
pub fn from_value_as_default(value: JsValue, context: &mut Context) -> Self {
Module::synthetic(
&[js_string!("default")],
SyntheticModuleInitializer::from_copy_closure_with_captures(
move |m, value, _ctx| {
m.set_export(&js_string!("default"), value.clone())?;
Ok(())
},
value,
),
None,
None,
context,
)
}
/// Create a module that exports a single JSON value as the default export, from its
/// JSON string.
///
/// # Specification
/// This is a custom extension to the ECMAScript specification. The current proposal
/// for JSON modules is being considered in <https://github.com/tc39/proposal-json-modules>
/// and might differ from this implementation.
///
/// This method is provided as a convenience for hosts to create JSON modules.
///
/// # Errors
/// This will return an error if the JSON string is invalid or cannot be converted.
pub fn parse_json(json: JsString, context: &mut Context) -> JsResult<Self> {
let value = builtins::Json::parse(&JsValue::undefined(), &[json.into()], context)?;
Ok(Self::from_value_as_default(value, context))
}
/// Gets the realm of this `Module`.
#[inline]
#[must_use]

65
core/engine/tests/module.rs

@ -0,0 +1,65 @@
#![allow(unused_crate_dependencies, missing_docs)]
use std::rc::Rc;
use boa_engine::builtins::promise::PromiseState;
use boa_engine::module::{ModuleLoader, Referrer};
use boa_engine::{js_string, Context, JsResult, JsString, Module, Source};
#[test]
fn test_json_module_from_str() {
struct TestModuleLoader(JsString);
impl ModuleLoader for TestModuleLoader {
fn load_imported_module(
&self,
_referrer: Referrer,
specifier: JsString,
finish_load: Box<dyn FnOnce(JsResult<Module>, &mut Context)>,
context: &mut Context,
) {
assert_eq!(specifier.to_std_string_escaped(), "basic");
finish_load(
Ok(Module::parse_json(self.0.clone(), context).unwrap()),
context,
);
}
}
let json_string = js_string!(r#"{"key":"value","other":123}"#);
let mut context = Context::builder()
.module_loader(Rc::new(TestModuleLoader(json_string.clone())))
.build()
.unwrap();
let source = Source::from_bytes(
b"
import basic_json from 'basic';
export let json = basic_json;
",
);
let module = Module::parse(source, None, &mut context).unwrap();
let promise = module.load_link_evaluate(&mut context);
context.run_jobs();
match promise.state() {
PromiseState::Pending => {}
PromiseState::Fulfilled(v) => {
assert!(v.is_undefined());
}
PromiseState::Rejected(e) => {
panic!("Unexpected error: {:?}", e.to_string(&mut context).unwrap());
}
}
let json = module
.namespace(&mut context)
.get(js_string!("json"), &mut context)
.unwrap();
assert_eq!(
JsString::from(json.to_json(&mut context).unwrap().to_string()),
json_string
);
}
Loading…
Cancel
Save