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

Add support for enum renames and refactor analyzer interface #71

Merged
merged 5 commits into from
May 3, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Simpler analyze entry-point for tests and main
for #70

Signed-off-by: clux <sszynrae@gmail.com>
  • Loading branch information
clux committed May 3, 2022
commit eace6ac1a8b03bcbedb64fb8fc9200ee659966fb
47 changes: 24 additions & 23 deletions src/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,24 @@ use std::collections::{BTreeMap, HashMap};

const IGNORED_KEYS: [&str; 3] = ["metadata", "apiVersion", "kind"];

/// Scan a schema for structs and members, and recurse to find all structs
///
/// All found output structs will have its names prefixed by the kind it is for
pub fn analyze(schema: JSONSchemaProps, kind: &str) -> Result<Vec<OutputStruct>> {
let mut res = vec![];
analyze_(schema, "", kind, 0, &mut res)?;
Ok(res)
}


/// Scan a schema for structs and members, and recurse to find all structs
///
/// schema: root schema / sub schema
/// current: current key name (or empty string for first call) - must capitalize first letter
/// stack: stacked concat of kind + current_{n-1} + ... + current (used to create dedup names/types)
/// level: recursion level (start at 0)
/// results: multable list of generated structs (not deduplicated)
pub fn analyze(
fn analyze_(
schema: JSONSchemaProps,
current: &str,
stack: &str,
Expand Down Expand Up @@ -74,21 +84,21 @@ pub fn analyze(
if dict_type == "array" {
// unpack the inner object from the array wrap
if let Some(JSONSchemaPropsOrArray::Schema(items)) = &s.as_ref().items {
analyze(*items.clone(), &next_key, &next_stack, level + 1, results)?;
analyze_(*items.clone(), &next_key, &next_stack, level + 1, results)?;
handled_inner = true;
}
}
// TODO: not sure if these nested recurses are necessary - cluster test case does not have enough data
//if let Some(extra_props) = &s.properties {
// for (_key, value) in extra_props {
// debug!("nested recurse into {} {} - key: {}", next_key, next_stack, _key);
// analyze(value.clone(), &next_key, &next_stack, level +1, results)?;
// analyze_(value.clone(), &next_key, &next_stack, level +1, results)?;
// }
//}
}
if !handled_inner {
// normal object recurse
analyze(value, &next_key, &next_stack, level + 1, results)?;
analyze_(value, &next_key, &next_stack, level + 1, results)?;
}
}
"array" => {
Expand All @@ -108,7 +118,7 @@ pub fn analyze(
bail!("could not recurse into vec");
}
}
analyze(inner, &next_key, &next_stack, level + 1, results)?;
analyze_(inner, &next_key, &next_stack, level + 1, results)?;
}
}
"" => {
Expand Down Expand Up @@ -480,8 +490,7 @@ mod test {
let schema: JSONSchemaProps = serde_yaml::from_str(schema_str).unwrap();
//println!("schema: {}", serde_json::to_string_pretty(&schema).unwrap());

let mut structs = vec![];
analyze(schema, "ValidationsInfo", "Agent", 0, &mut structs).unwrap();
let structs = analyze(schema, "Agent").unwrap();
//println!("{:?}", structs);
let root = &structs[0];
assert_eq!(root.name, "Agent");
Expand Down Expand Up @@ -525,8 +534,7 @@ type: object
"#;
let schema: JSONSchemaProps = serde_yaml::from_str(schema_str).unwrap();
//println!("schema: {}", serde_json::to_string_pretty(&schema).unwrap());
let mut structs = vec![];
analyze(schema, "Selector", "Server", 0, &mut structs).unwrap();
let structs = analyze(schema, "Server").unwrap();
//println!("{:#?}", structs);

let root = &structs[0];
Expand Down Expand Up @@ -557,16 +565,15 @@ type: object
"#;
let schema: JSONSchemaProps = serde_yaml::from_str(schema_str).unwrap();

let mut structs = vec![];
analyze(schema, "ServerSpec", "Server", 0, &mut structs).unwrap();
let structs = analyze(schema, "Server").unwrap();
let root = &structs[0];
assert_eq!(root.name, "Server");
assert_eq!(root.level, 0);
// should have an IntOrString member:
let member = &root.members[0];
assert_eq!(member.name, "port");
assert_eq!(member.type_, "IntOrString");
assert!(root.uses_int_or_string());
// TODO: check that anyOf: [type: integer, type: string] also works
}

#[test]
Expand All @@ -587,8 +594,7 @@ type: object
"#;

let schema: JSONSchemaProps = serde_yaml::from_str(schema_str).unwrap();
let mut structs = vec![];
analyze(schema, "", "MatchExpressions", 0, &mut structs).unwrap();
let structs = analyze(schema, "MatchExpressions").unwrap();
println!("got {:?}", structs);
let root = &structs[0];
assert_eq!(root.name, "MatchExpressions");
Expand Down Expand Up @@ -641,8 +647,7 @@ type: object
"#;

let schema: JSONSchemaProps = serde_yaml::from_str(schema_str).unwrap();
let mut structs = vec![];
analyze(schema, "", "Endpoint", 0, &mut structs).unwrap();
let structs = analyze(schema, "Endpoint").unwrap();
println!("got {:?}", structs);
let root = &structs[0];
assert_eq!(root.name, "Endpoint");
Expand Down Expand Up @@ -726,8 +731,7 @@ type: object
type: object"#;

let schema: JSONSchemaProps = serde_yaml::from_str(schema_str).unwrap();
let mut structs = vec![];
analyze(schema, "", "ServerSpec", 0, &mut structs).unwrap();
let structs = analyze(schema, "ServerSpec").unwrap();
println!("got {:?}", structs);
let root = &structs[0];
assert_eq!(root.name, "ServerSpec");
Expand Down Expand Up @@ -799,8 +803,7 @@ type: object
type: object
"#;
let schema: JSONSchemaProps = serde_yaml::from_str(schema_str).unwrap();
let mut structs = vec![];
analyze(schema, "Endpoints", "ServiceMonitor", 0, &mut structs).unwrap();
let structs = analyze(schema, "ServiceMonitor").unwrap();
println!("got {:?}", structs);
let root = &structs[0];
assert_eq!(root.name, "ServiceMonitor");
Expand Down Expand Up @@ -864,14 +867,12 @@ type: object
let schema: JSONSchemaProps = serde_yaml::from_str(schema_str).unwrap();

//println!("schema: {}", serde_json::to_string_pretty(&schema).unwrap());
let mut structs = vec![];
analyze(schema, "LocalityLbSetting", "DestinationRule", 1, &mut structs).unwrap();
let structs = analyze(schema, "DestinationRule").unwrap();
//println!("{:#?}", structs);

// this should produce the root struct struct
let root = &structs[0];
assert_eq!(root.name, "DestinationRule");
assert_eq!(root.level, 1);
// which contains the distribute member:
let distmember = &root.members[0];
assert_eq!(distmember.name, "distribute");
Expand Down
40 changes: 2 additions & 38 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,6 @@
#[macro_use] extern crate log;

/// Output struct from analysis
#[derive(Default, Debug)]
pub struct OutputStruct {
// The short name of the struct (kind + capitalized suffix)
pub name: String,
pub level: u8,
pub members: Vec<OutputMember>,
pub docs: Option<String>,
pub is_enum: bool,
}

/// Output member belonging to an OutputStruct
#[derive(Default, Debug)]
pub struct OutputMember {
pub name: String,
pub type_: String,
pub serde_annot: Vec<String>,
pub docs: Option<String>,
}

impl OutputStruct {
pub fn uses_btreemaps(&self) -> bool {
self.members.iter().any(|m| m.type_.contains("BTreeMap"))
}

pub fn uses_datetime(&self) -> bool {
self.members.iter().any(|m| m.type_.contains("DateTime"))
}

pub fn uses_date(&self) -> bool {
self.members.iter().any(|m| m.type_.contains("NaiveDate"))
}

pub fn uses_int_or_string(&self) -> bool {
self.members.iter().any(|m| m.type_.contains("IntOrString"))
}
}

mod analyzer;
pub use analyzer::analyze;
mod output;
pub use output::{OutputMember, OutputStruct};
3 changes: 1 addition & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,8 @@ impl Kopium {
let scope = &crd.spec.scope;

if let Some(schema) = data {
let mut structs = vec![];
log::debug!("schema: {}", serde_json::to_string_pretty(&schema)?);
analyze(schema, "", &kind, 0, &mut structs)?;
let structs = analyze(schema, &kind)?;

if !self.hide_prelude {
self.print_prelude(&structs);
Expand Down
37 changes: 37 additions & 0 deletions src/output.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/// Output struct from analysis
#[derive(Default, Debug)]
pub struct OutputStruct {
// The short name of the struct (kind + capitalized suffix)
pub name: String,
pub level: u8,
pub members: Vec<OutputMember>,
pub docs: Option<String>,
pub is_enum: bool,
}

/// Output member belonging to an OutputStruct
#[derive(Default, Debug)]
pub struct OutputMember {
pub name: String,
pub type_: String,
pub serde_annot: Vec<String>,
pub docs: Option<String>,
}

impl OutputStruct {
pub fn uses_btreemaps(&self) -> bool {
self.members.iter().any(|m| m.type_.contains("BTreeMap"))
}

pub fn uses_datetime(&self) -> bool {
self.members.iter().any(|m| m.type_.contains("DateTime"))
}

pub fn uses_date(&self) -> bool {
self.members.iter().any(|m| m.type_.contains("NaiveDate"))
}

pub fn uses_int_or_string(&self) -> bool {
self.members.iter().any(|m| m.type_.contains("IntOrString"))
}
}