Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support external references #621

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Prev Previous commit
Next Next commit
fmt
SRetip committed Jul 1, 2024
commit 074d39734ecfe30d154bf1cb8be9b9cb2fa45294
71 changes: 35 additions & 36 deletions typify-impl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -220,7 +220,6 @@ pub struct TypeSpace {
}

impl TypeSpace {

/// Sets the file path for the `TypeSpace` instance.
pub fn with_path<T: Into<PathBuf>>(&mut self, path: T) {
self.file_path = path.into().canonicalize().unwrap();
@@ -1262,36 +1261,36 @@ impl<'a> TypeNewtype<'a> {
}

fn fetch_external_definitions(
base_schema: &RootSchema, // Reference to the base schema
definition: &Schema, // The schema definition to process
base_path: &PathBuf, // Base path for file operations
base_id: &Option<String>, // Optional base ID for schema
external_references: &mut BTreeMap<RefKey, (Schema, PathBuf, Option<String>)>, // Map to store external references
first_run: bool, // Flag to indicate if this is the first run of the function
base_schema: &RootSchema, // Reference to the base schema
definition: &Schema, // The schema definition to process
base_path: &PathBuf, // Base path for file operations
base_id: &Option<String>, // Optional base ID for schema
external_references: &mut BTreeMap<RefKey, (Schema, PathBuf, Option<String>)>, // Map to store external references
first_run: bool, // Flag to indicate if this is the first run of the function
) {
// Iterate through each reference found in the given schema definition
for mut reference in get_references(&definition) {
if reference.is_empty() {
continue; // Skip empty references
continue; // Skip empty references
}
if reference.starts_with("#") {
// Handle internal references
if first_run {
continue; // Skip processing internal references on the first run
continue; // Skip processing internal references on the first run
}

reference.remove(0); // Remove the '#' character from the reference
reference.remove(0); // Remove the '#' character from the reference
let fragment = reference
.split("/")
.into_iter()
.map(|s| s.to_string())
.filter(|s| !s.is_empty())
.collect(); // Split and collect the reference into a vector of strings
let definition_schema = fetch_defenition(base_schema, &reference, &fragment); // Fetch the internal schema definition
let k = format!("{}{}", base_id.as_ref().unwrap(), reference); // Create a key for the reference
.split("/")
.into_iter()
.map(|s| s.to_string())
.filter(|s| !s.is_empty())
.collect(); // Split and collect the reference into a vector of strings
let definition_schema = fetch_defenition(base_schema, &reference, &fragment); // Fetch the internal schema definition
let k = format!("{}{}", base_id.as_ref().unwrap(), reference); // Create a key for the reference
let key = RefKey::Def(k);
if external_references.contains_key(&key) {
continue; // Skip if the reference already exists in the map
continue; // Skip if the reference already exists in the map
} else {
// Insert the reference into the map and recursively fetch external definitions
external_references.insert(
@@ -1314,34 +1313,34 @@ fn fetch_external_definitions(
} else {
// Handle external references
let base_id = base_id
.as_ref()
.expect("missing 'id' attribute in schema definition"); // Ensure base_id is present
let id = Iri::new(base_id).unwrap(); // Create an IRI from the base ID
let reff = Iri::new(&reference).unwrap(); // Create an IRI from the reference
.as_ref()
.expect("missing 'id' attribute in schema definition"); // Ensure base_id is present
let id = Iri::new(base_id).unwrap(); // Create an IRI from the base ID
let reff = Iri::new(&reference).unwrap(); // Create an IRI from the reference
let fragment = reff
.fragment()
.as_ref()
.unwrap_or(&FragmentBuf::new("".to_string()).unwrap().as_fragment())
.to_string()
.split("/")
.filter_map(|s| (!s.is_empty()).then_some(s.to_string()))
.collect::<Vec<_>>(); // Process the fragment part of the reference
.fragment()
.as_ref()
.unwrap_or(&FragmentBuf::new("".to_string()).unwrap().as_fragment())
.to_string()
.split("/")
.filter_map(|s| (!s.is_empty()).then_some(s.to_string()))
.collect::<Vec<_>>(); // Process the fragment part of the reference
let relpath =
diff_paths(reff.path().as_str(), id.path().parent_or_empty().as_str()).unwrap(); // Determine the relative path
let file_path = base_path.parent().unwrap().join(&relpath); // Construct the file path
diff_paths(reff.path().as_str(), id.path().parent_or_empty().as_str()).unwrap(); // Determine the relative path
let file_path = base_path.parent().unwrap().join(&relpath); // Construct the file path
let content = std::fs::read_to_string(&file_path).expect(&format!(
"Failed to open input file: {}",
&file_path.display()
)); // Read the file content
)); // Read the file content

let root_schema = serde_json::from_str::<RootSchema>(&content)
.expect("Failed to parse input file as JSON Schema"); // Parse the file content as JSON Schema
let definition_schema = fetch_defenition(&root_schema, &reference, &fragment); // Fetch the external schema definition
.expect("Failed to parse input file as JSON Schema"); // Parse the file content as JSON Schema
let definition_schema = fetch_defenition(&root_schema, &reference, &fragment); // Fetch the external schema definition
let key = RefKey::Def(reference.clone());
if external_references.contains_key(&key) {
continue; // Skip if the reference already exists in the map
continue; // Skip if the reference already exists in the map
} else {
let s_id = get_schema_id(&root_schema.schema); // Get the schema ID
let s_id = get_schema_id(&root_schema.schema); // Get the schema ID

// Insert the reference into the map and recursively fetch external definitions
external_references.insert(
26 changes: 13 additions & 13 deletions typify-impl/tests/test_external_references.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
use schemars::schema::RootSchema;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use schemars::schema::RootSchema;
use typify_impl::TypeSpace;

#[test]
fn test_external_references() {
let mut type_space = TypeSpace::default();
let mut type_space = TypeSpace::default();

let path = Path::new("tests/external_references.json");
let file = File::open(path).unwrap();
let reader = BufReader::new(file);
let path = Path::new("tests/external_references.json");
let file = File::open(path).unwrap();
let reader = BufReader::new(file);

let schema: RootSchema = serde_json::from_reader(reader).unwrap();
// schema.schema.metadata().title = Some("Everything".to_string());
type_space.with_path("tests/external_references.json");
type_space.add_root_schema(schema).unwrap();
let schema: RootSchema = serde_json::from_reader(reader).unwrap();
// schema.schema.metadata().title = Some("Everything".to_string());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

commented out code in this test

type_space.with_path("tests/external_references.json");
type_space.add_root_schema(schema).unwrap();

let file = type_space.to_stream();
let file = type_space.to_stream();

let fmt = rustfmt_wrapper::rustfmt(file.to_string()).unwrap();
println!("{fmt}");
let fmt = rustfmt_wrapper::rustfmt(file.to_string()).unwrap();
println!("{fmt}");

expectorate::assert_contents("tests/external_references.out", fmt.as_str());
expectorate::assert_contents("tests/external_references.out", fmt.as_str());
}