Skip to content

Commit

Permalink
feat: Add support for importing yaml files
Browse files Browse the repository at this point in the history
Signed-off-by: Yoriyasu Yano <430092+yorinasub17@users.noreply.github.com>
  • Loading branch information
yorinasub17 committed Dec 4, 2023
1 parent b6d5d30 commit 30e2e86
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 97 deletions.
114 changes: 36 additions & 78 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,101 +450,36 @@ mod tests {
static EXPECTED_RELPATH_OUTPUT_JSON: &str =
"{\"state\":\"aws/us-east-1/vpc/terraform.tfstate\",\"mainf\":\"aws/us-east-1/vpc/main.js\"}";
static EXPECTED_OUTFILE_OUTPUT_JSON: &str = "{\"this\":\"outfile.js\"}";
static EXPECTED_IMPORT_CONFIG_OUTPUT_JSON: &str = "{\"msg\":\"hello world\"}";

#[tokio::test]
async fn test_engine_runs_js() {
let expected_output: serde_json::Value = serde_json::from_str(EXPECTED_SIMPLE_OUTPUT_JSON)
.expect("error unpacking simple expected output json");

let p = get_fixture_path("simple.js");
let req = RunRequest {
in_file: String::from(p.as_path().to_string_lossy()),
out_file_stem: String::from(""),
};
let od_vec = run_js(&get_context(), &req)
.await
.expect("error running js");
assert_eq!(od_vec.len(), 1);
let od = &od_vec[0];

assert_eq!(od.out_path, None);
assert_eq!(od.out_ext, Some(String::from(".json")));
assert_eq!(od.out_prefix, None);
let actual_output: serde_json::Value =
serde_json::from_str(&od.data).expect("error unpacking js data");
assert_eq!(actual_output, expected_output);
check_single_json_output(EXPECTED_SIMPLE_OUTPUT_JSON, "simple.js").await;
}

#[tokio::test]
async fn test_engine_runs_ts() {
let expected_output: serde_json::Value = serde_json::from_str(EXPECTED_SIMPLE_OUTPUT_JSON)
.expect("error unpacking simple expected output json");
check_single_json_output(EXPECTED_SIMPLE_OUTPUT_JSON, "simple.ts").await;
}

let p = get_fixture_path("simple.ts");
let req = RunRequest {
in_file: String::from(p.as_path().to_string_lossy()),
out_file_stem: String::from(""),
};
let od_vec = run_js(&get_context(), &req)
.await
.expect("error running js");
assert_eq!(od_vec.len(), 1);
let od = &od_vec[0];
#[tokio::test]
async fn test_engine_runs_code_with_config_json_import() {
check_single_json_output(EXPECTED_IMPORT_CONFIG_OUTPUT_JSON, "import_json.js").await;
}

assert_eq!(od.out_path, None);
assert_eq!(od.out_ext, Some(String::from(".json")));
assert_eq!(od.out_prefix, None);
let actual_output: serde_json::Value =
serde_json::from_str(&od.data).expect("error unpacking js data");
assert_eq!(actual_output, expected_output);
#[tokio::test]
async fn test_engine_runs_code_with_config_yaml_import() {
check_single_json_output(EXPECTED_IMPORT_CONFIG_OUTPUT_JSON, "import_yaml.js").await;
}

#[tokio::test]
async fn test_engine_runs_code_with_node_modules() {
let expected_output: serde_json::Value = serde_json::from_str(EXPECTED_LODASH_OUTPUT_JSON)
.expect("error unpacking lodash expected output json");

let p = get_fixture_path("with_lodash.js");
let req = RunRequest {
in_file: String::from(p.as_path().to_string_lossy()),
out_file_stem: String::from(""),
};
let od_vec = run_js(&get_context(), &req)
.await
.expect("error running js");
assert_eq!(od_vec.len(), 1);
let od = &od_vec[0];

assert_eq!(od.out_path, None);
assert_eq!(od.out_ext, Some(String::from(".json")));
assert_eq!(od.out_prefix, None);
let actual_output: serde_json::Value =
serde_json::from_str(&od.data).expect("error unpacking js data");
assert_eq!(actual_output, expected_output);
check_single_json_output(EXPECTED_LODASH_OUTPUT_JSON, "with_lodash.js").await;
}

#[tokio::test]
async fn test_engine_runs_code_with_builtin_filefunctions() {
let expected_output: serde_json::Value = serde_json::from_str(EXPECTED_RELPATH_OUTPUT_JSON)
.expect("error unpacking relpath output json");

let p = get_fixture_path("aws/us-east-1/vpc/main.js");
let req = RunRequest {
in_file: String::from(p.as_path().to_string_lossy()),
out_file_stem: String::from(""),
};
let od_vec = run_js(&get_context(), &req)
.await
.expect("error running js");
assert_eq!(od_vec.len(), 1);
let od = &od_vec[0];

assert_eq!(od.out_path, None);
assert_eq!(od.out_ext, Some(String::from(".json")));
assert_eq!(od.out_prefix, None);
let actual_output: serde_json::Value =
serde_json::from_str(&od.data).expect("error unpacking js data");
assert_eq!(actual_output, expected_output);
check_single_json_output(EXPECTED_RELPATH_OUTPUT_JSON, "aws/us-east-1/vpc/main.js").await;
}

#[tokio::test]
Expand Down Expand Up @@ -685,6 +620,29 @@ mod tests {
let _ = step_result.expect("wrong output");
}

async fn check_single_json_output(output_json_str: &str, fixture_fname: &str) {
let expected_output: serde_json::Value =
serde_json::from_str(output_json_str).expect("error unpacking expected output json");

let p = get_fixture_path(fixture_fname);
let req = RunRequest {
in_file: String::from(p.as_path().to_string_lossy()),
out_file_stem: String::from(""),
};
let od_vec = run_js(&get_context(), &req)
.await
.expect("error running js");
assert_eq!(od_vec.len(), 1);
let od = &od_vec[0];

assert_eq!(od.out_path, None);
assert_eq!(od.out_ext, Some(String::from(".json")));
assert_eq!(od.out_prefix, None);
let actual_output: serde_json::Value =
serde_json::from_str(&od.data).expect("error unpacking js data");
assert_eq!(actual_output, expected_output);
}

fn get_context() -> Context {
let node_modules_dir = Some(get_fixture_path("node_modules"));
let projectroot = get_fixture_path("");
Expand Down
62 changes: 43 additions & 19 deletions src/module_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ use deno_core::futures::FutureExt;
use deno_core::*;
use log::*;

// The transpile type. Determines how the code should be transpiled before loading.
enum TranspileType {
No, // No transpilation.
Typescript, // Transpile typescript files to javascript.
YAML, // Transpile yaml files to json.
}

// The TypeScript module loader.
// This will check to see if the file is a TypeScript file, and run those through swc to transpile
// to JS.
Expand Down Expand Up @@ -89,7 +96,7 @@ impl ModuleLoader for TsModuleLoader {
// If there is no extension, assume .ts or .js (in that order) depending on if the path
// exists.
let path = match orig_path.extension() {
Some(_) => orig_path,
Some(_) => orig_path.clone(),
None => {
let mut maybe_ts = orig_path.clone();
maybe_ts.set_extension("ts");
Expand All @@ -108,38 +115,55 @@ impl ModuleLoader for TsModuleLoader {
// Determine what the MediaType is (this is done based on the file
// extension) and whether transpiling is required.
let media_type = MediaType::from_path(&path);
let (module_type, should_transpile) = match media_type {
let (module_type, transpile_type) = match media_type {
MediaType::JavaScript | MediaType::Mjs | MediaType::Cjs => {
(ModuleType::JavaScript, false)
(ModuleType::JavaScript, TranspileType::No)
}
MediaType::Jsx => (ModuleType::JavaScript, true),
MediaType::Jsx => (ModuleType::JavaScript, TranspileType::Typescript),
MediaType::TypeScript
| MediaType::Mts
| MediaType::Cts
| MediaType::Dts
| MediaType::Dmts
| MediaType::Dcts
| MediaType::Tsx => (ModuleType::JavaScript, true),
MediaType::Json => (ModuleType::Json, false),
| MediaType::Tsx => (ModuleType::JavaScript, TranspileType::Typescript),
MediaType::Json => (ModuleType::Json, TranspileType::No),
_ => {
return Err(anyhow!("Unknown extension {:?}", path.extension()));
let e = Err(anyhow!("Unknown extension {:?}", path.extension()));
match orig_path.extension() {
Some(os_str) => {
let lowercase_str = os_str.to_str().map(|s| s.to_lowercase());
match lowercase_str.as_deref() {
Some("yaml") | Some("yml") => {
(ModuleType::Json, TranspileType::YAML)
}
_ => return e,
}
}
_ => return e,
}
}
};

// Read the file, transpile if necessary.
let code = fs::read_to_string(&path)?;
let code = if should_transpile {
let parsed = deno_ast::parse_module(ParseParams {
specifier: module_specifier.to_string(),
text_info: SourceTextInfo::from_string(code),
media_type,
capture_tokens: false,
scope_analysis: false,
maybe_syntax: None,
})?;
parsed.transpile(&Default::default())?.text
} else {
code
let code = match transpile_type {
TranspileType::No => code,
TranspileType::Typescript => {
let parsed = deno_ast::parse_module(ParseParams {
specifier: module_specifier.to_string(),
text_info: SourceTextInfo::from_string(code),
media_type,
capture_tokens: false,
scope_analysis: false,
maybe_syntax: None,
})?;
parsed.transpile(&Default::default())?.text
}
TranspileType::YAML => {
let parsed: serde_json::Value = serde_yaml::from_str(&code)?;
serde_json::to_string(&parsed)?
}
};

// Load and return module.
Expand Down
8 changes: 8 additions & 0 deletions tests/fixtures/import_json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright (c) Fensak, LLC.
// SPDX-License-Identifier: MPL-2.0

import cfg from "./someconfig.json" with { type: "json" };

export function main() {
return cfg;
}
8 changes: 8 additions & 0 deletions tests/fixtures/import_yaml.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright (c) Fensak, LLC.
// SPDX-License-Identifier: MPL-2.0

import cfg from "./someconfig.yaml" with { type: "json" };

export function main() {
return cfg;
}
3 changes: 3 additions & 0 deletions tests/fixtures/someconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"msg": "hello world"
}
1 change: 1 addition & 0 deletions tests/fixtures/someconfig.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
msg: "hello world"

0 comments on commit 30e2e86

Please # to comment.