Skip to content

Commit

Permalink
Implement JSON modules (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
andreubotella authored Jan 21, 2024
1 parent 21207fc commit 21adcfd
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 42 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,21 @@ easily copied.
This crate provides a simple implementation of `ModuleLoader` that does load
modules from the network, built on top of `reqwest`.

Things it supports or aims to support:
Things it supports:

- HTTP(S) imports
- Local filesystem imports
- Data URLs
- JSON modules (i.e. import assertions will just work) (pending)
- JSON modules (i.e. `{type: "json"}` import attributes just work)

Things it doesn't plan to support (but hey, file an issue if it bugs you):

- Any support at all for non-URL import specifiers (i.e. bare imports, like
`"lodash"`), URL specifiers which are not supported in browsers (like Deno's
`npm:` URL support), or any other mapping from the import specifier to the
actual fetched URL (like import maps).
- Custom import attribute types (such as `{type: "my-custom-type"}`). CSS
imports count as a custom type for this purpose.
- Blob URLs
- Any support for transpiling modules (i.e. Typescript)
- Custom network, authentication or TLS settings. (Though if there's significant
Expand Down
17 changes: 12 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl ModuleLoader for SimpleModuleLoader {
module_specifier: &ModuleSpecifier,
_maybe_referrer: Option<&ModuleSpecifier>,
_is_dyn_import: bool,
_requested_module_type: RequestedModuleType,
requested_module_type: RequestedModuleType,
) -> Pin<Box<ModuleSourceFuture>> {
let module_specifier = module_specifier.clone();

Expand Down Expand Up @@ -67,18 +67,25 @@ impl ModuleLoader for SimpleModuleLoader {
schema => bail!("Invalid schema {}", schema),
};

// TODO: The MIME types should probably be checked.
let module_type = match requested_module_type {
RequestedModuleType::None => ModuleType::JavaScript,
RequestedModuleType::Json => ModuleType::Json,
RequestedModuleType::Other(_) => {
unreachable!("Import types other than JSON are not supported")
}
};

if let Some(redirect_module_url) = redirect_module_url {
Ok(ModuleSource::new_with_redirect(
// TODO: JSON modules.
ModuleType::JavaScript,
module_type,
ModuleSourceCode::Bytes(bytes.into_boxed_slice().into()),
&module_specifier,
&redirect_module_url,
))
} else {
Ok(ModuleSource::new(
// TODO: JSON modules.
ModuleType::JavaScript,
module_type,
ModuleSourceCode::Bytes(bytes.into_boxed_slice().into()),
&module_specifier,
))
Expand Down
6 changes: 6 additions & 0 deletions tests/files/json_import_main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import jsonTest1 from "./json_test1.json" with {type: "json"};

console.log(JSON.stringify(jsonTest1));

const jsonModuleNamespace = await import("./json_test2.json", {with: {type: "json"}});
console.log(JSON.stringify(jsonModuleNamespace));
4 changes: 4 additions & 0 deletions tests/files/json_test1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"a": [42],
"dsjflks": null
}
1 change: 1 addition & 0 deletions tests/files/json_test2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["a", "b", "c", 42, null, "d"]
76 changes: 41 additions & 35 deletions tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,43 +115,49 @@ fn get_output(runtime: &mut JsRuntime) -> Result<String, Error> {
Ok(serde_v8::from_v8(scope, local_value)?)
}

#[tokio::test]
async fn basic_test() -> Result<(), Error> {
ensure_server_is_running().await;
macro_rules! test {
(name: $name:ident, path: $path:literal, expected: $expected:expr) => {
#[tokio::test]
async fn $name() -> Result<(), Error> {
ensure_server_is_running().await;

let mut runtime = setup_runtime()?;
let module_id = runtime
.load_main_module(&url_from_test_path($path), None)
.await?;
let receiver = runtime.mod_evaluate(module_id);
runtime.run_event_loop(Default::default()).await?;
receiver.await?;

assert_eq!(get_output(&mut runtime)?, $expected);

Ok(())
}
};
}

let mut runtime = setup_runtime()?;
let module_id = runtime
.load_main_module(&url_from_test_path("basic_main.js"), None)
.await?;
let receiver = runtime.mod_evaluate(module_id);
runtime.run_event_loop(Default::default()).await?;
receiver.await?;

assert_eq!(
get_output(&mut runtime)?,
format!(
"test1.js http://localhost:8888/test1.js\nbasic_main.js {}\nData URL value: 42\n",
url_from_test_path("basic_main.js")
)
);
Ok(())
test! {
name: basic_test,
path: "basic_main.js",
expected: format!(
"test1.js http://localhost:8888/test1.js\nbasic_main.js {}\nData URL value: 42\n",
url_from_test_path("basic_main.js")
)
}

#[tokio::test]
async fn http_redirect_test() -> Result<(), Error> {
ensure_server_is_running().await;
test! {
name: http_redirect_test,
path: "http_redirect_main.js",
expected: "test1.js http://localhost:8888/test1.js\n"
}

let mut runtime = setup_runtime()?;
let module_id = runtime
.load_main_module(&url_from_test_path("http_redirect_main.js"), None)
.await?;
let receiver = runtime.mod_evaluate(module_id);
runtime.run_event_loop(Default::default()).await?;
receiver.await?;

assert_eq!(
get_output(&mut runtime)?,
"test1.js http://localhost:8888/test1.js\n"
);
Ok(())
test! {
name: json_import_test,
path: "json_import_main.js",
expected: concat!(
r#"{"a":[42],"dsjflks":null}"#,
"\n",
r#"{"default":["a","b","c",42,null,"d"]}"#,
"\n"
)
}

0 comments on commit 21adcfd

Please sign in to comment.