Skip to content
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
3 changes: 3 additions & 0 deletions example/specs/basic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ channels:
message:
payload:
type: object
properties:
name:
type: string
publish:
operationId: userSingedUp
summary: send welcome email to user
Expand Down
1 change: 1 addition & 0 deletions example/specs/basic_ref.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ servers:
channels:
user/signedup:
subscribe:
operationId: onUserSignup
message:
$ref: "#/components/messages/userSignUp"
components:
Expand Down
13 changes: 8 additions & 5 deletions src/parser/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ use regex::Regex;

use crate::asyncapi_model::AsyncAPI;

pub fn parse_spec_to_model(path: &Path) -> Result<AsyncAPI, serde_yaml::Error> {
pub fn parse_spec_to_model(path: &Path) -> Result<AsyncAPI, serde_json::Error> {
let string_content = fs::read_to_string(path).expect("file could not be read");
// check if file is yaml or json
let parsed = match path.extension() {
Some(ext) => match ext.to_str() {
Some("yaml") => serde_yaml::from_str::<AsyncAPI>(&string_content).unwrap(),
Some("yml") => serde_yaml::from_str::<AsyncAPI>(&string_content).unwrap(),
Some("json") => serde_json::from_str::<AsyncAPI>(&string_content).unwrap(),
Some("yaml") => serde_yaml::from_str::<serde_json::Value>(&string_content).unwrap(),
Some("yml") => serde_yaml::from_str::<serde_json::Value>(&string_content).unwrap(),
Some("json") => serde_json::from_str::<serde_json::Value>(&string_content).unwrap(),
_ => {
panic!("file has no extension");
}
Expand All @@ -21,7 +21,10 @@ pub fn parse_spec_to_model(path: &Path) -> Result<AsyncAPI, serde_yaml::Error> {
panic!("file has no extension");
}
};
Ok(parsed)
let with_resolved_references =
crate::parser::resolve_refs::resolve_refs(parsed.clone(), parsed);
let spec = serde_json::from_value::<AsyncAPI>(with_resolved_references)?;
Ok(spec)
}

fn capitalize_first_char(s: &str) -> String {
Expand Down
2 changes: 2 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
mod common;
mod pubsub;
mod resolve_refs;
mod schema_parser;
pub use common::parse_spec_to_model;
pub use pubsub::spec_to_pubsub_template_type;
pub use resolve_refs::resolve_refs;
pub use schema_parser::schema_parser_mapper;
1 change: 1 addition & 0 deletions src/parser/pubsub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ pub fn spec_to_pubsub_template_type<'a>(
server,
subscribe_channels,
publish_channels,
schema: joined_schemas,
};
Ok(pubsub_template)
}
85 changes: 85 additions & 0 deletions src/parser/resolve_refs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
pub fn resolve_json_path(json: serde_json::Value, path: &str) -> serde_json::Value {
let parts = path.split('/').collect::<Vec<&str>>();
let mut current_json = json;
for part in parts {
current_json = current_json[part].clone();
}
current_json
}

pub fn resolve_refs(json: serde_json::Value, root_json: serde_json::Value) -> serde_json::Value {
match json {
serde_json::Value::Object(map) => {
let mut new_map = serde_json::Map::new();
for (key, value) in map {
if key == "$ref" {
if let serde_json::Value::String(string_val) = value {
let correct_json = resolve_json_path(
root_json.clone(),
string_val.trim_start_matches("#/"),
);
return resolve_refs(correct_json, root_json);
} else {
panic!("$ref value is not a string");
}
}
let new_value = resolve_refs(value, root_json.clone());
new_map.insert(key, new_value);
}
serde_json::Value::Object(new_map)
}
serde_json::Value::Array(array) => {
let new_array = array
.into_iter()
.map(|value| resolve_refs(value, root_json.clone()))
.collect();
serde_json::Value::Array(new_array)
}
_ => json,
}
}

#[cfg(test)]
mod tests {
use std::{fs, path::Path};

use super::*;
use crate::*;

const SCHEMAS: [&str; 1] = ["./example/specs/basic_ref.yml"];

//parse file to json, allowed files are yaml and json
fn parse_test(path: &Path) -> serde_json::Value {
let string_content = fs::read_to_string(path).expect("file could not be read");
// check if file is yaml or json
let parsed: serde_json::Value = match path.extension() {
Some(ext) => match ext.to_str() {
Some("yaml") => serde_yaml::from_str::<serde_json::Value>(&string_content).unwrap(),
Some("yml") => serde_yaml::from_str::<serde_json::Value>(&string_content).unwrap(),
Some("json") => serde_json::from_str::<serde_json::Value>(&string_content).unwrap(),
_ => {
panic!("file has no extension");
}
},
None => {
panic!("file has no extension");
}
};
parsed
}

#[test]
fn resolves_refs() {
for schema_paths in SCHEMAS {
let definition = parse_test(Path::new(schema_paths));
let resolved: serde_json::Value = resolve_refs(definition.clone(), definition.clone());
let filename_without_extension = Path::new(schema_paths)
.file_stem()
.unwrap()
.to_str()
.unwrap();
let out_dir = Path::new("./test_output/{}.rs").join(filename_without_extension);
utils::write_to_path_create_dir(&resolved.to_string(), &out_dir).unwrap();
}
}
}
1 change: 1 addition & 0 deletions src/template_model/pubsub_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub struct PubsubTemplate<'a> {
pub server: &'a Server,
pub subscribe_channels: Vec<(&'a String, &'a Operation)>,
pub publish_channels: Vec<(&'a String, &'a Operation)>,
pub schema: String,
}

impl<'a> From<&PubsubTemplate<'a>> for gtmpl::Value {
Expand Down
2 changes: 2 additions & 0 deletions templates/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use std::time;
use async_nats::{Client, Message};
use crate::publish_message;

{{ .schema }}

{{ range .subscribe_channels }}
pub fn handler_{{ (index . 1).operationId }}(message: Message) {
println!("Received message {:#?}", message)
Expand Down