use serde_json::{json, Value};
pub fn type_names(sdl: &str) -> Vec<String> {
let mut names = Vec::new();
for line in sdl.lines() {
let t = line.trim();
for kw in [
"type ",
"input ",
"enum ",
"interface ",
"union ",
"scalar ",
] {
if let Some(rest) = t.strip_prefix(kw) {
if let Some(name) = rest
.split(|c: char| c.is_whitespace() || c == '{' || c == '(' || c == '=')
.next()
{
if !name.is_empty() {
names.push(name.to_string());
}
}
}
}
}
names
}
pub fn introspection_bytes(sdl: &str, format: &str) -> Vec<u8> {
if format.eq_ignore_ascii_case("JSON") {
let types: Vec<Value> = type_names(sdl)
.into_iter()
.map(|n| json!({ "kind": "OBJECT", "name": n }))
.collect();
let doc = json!({
"__schema": {
"queryType": { "name": "Query" },
"types": types,
}
});
serde_json::to_vec(&doc).unwrap_or_default()
} else {
sdl.as_bytes().to_vec()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_type_names() {
let sdl =
"type Query { hello: String }\ntype Post { id: ID! }\ninput NewPost { t: String }";
let names = type_names(sdl);
assert!(names.contains(&"Query".to_string()));
assert!(names.contains(&"Post".to_string()));
assert!(names.contains(&"NewPost".to_string()));
}
#[test]
fn sdl_format_is_verbatim() {
let sdl = "type Query { hello: String }";
assert_eq!(introspection_bytes(sdl, "SDL"), sdl.as_bytes());
}
#[test]
fn json_format_lists_types() {
let sdl = "type Query { hello: String }";
let bytes = introspection_bytes(sdl, "JSON");
let v: Value = serde_json::from_slice(&bytes).unwrap();
assert_eq!(v["__schema"]["types"][0]["name"], json!("Query"));
}
}