Skip to main content

rain_metadata/cli/schema/
show.rs

1use clap::Parser;
2use std::path::PathBuf;
3use schemars::schema_for;
4use crate::meta::KnownMeta;
5use crate::cli::output::SupportedOutputEncoding;
6
7#[derive(Parser)]
8pub struct Show {
9    /// One of a set of known JSON schemas that can be produced to match a subset
10    /// of the validation performed on known metas. Additional validation beyond
11    /// what can be expressed by JSON schema is performed when parsing and
12    /// validating metadata.
13    #[arg(value_parser = clap::value_parser!(KnownMeta))]
14    schema: KnownMeta,
15    /// If provided the schema will be written to the given path instead of
16    /// stdout.
17    #[arg(short, long)]
18    output_path: Option<PathBuf>,
19    /// If true the schema will be pretty printed. Defaults to false.
20    #[arg(short, long)]
21    pretty_print: bool,
22}
23
24pub fn show(s: Show) -> anyhow::Result<()> {
25    let schema_json = match s.schema {
26        KnownMeta::OpV1 => schema_for!(crate::meta::types::op::v1::OpMeta),
27        KnownMeta::AuthoringMetaV1 => schema_for!(crate::meta::types::authoring::v1::AuthoringMeta),
28        KnownMeta::SolidityAbiV2 => {
29            schema_for!(crate::meta::types::solidity_abi::v2::SolidityAbiMeta)
30        }
31        KnownMeta::InterpreterCallerMetaV1 => {
32            schema_for!(crate::meta::types::interpreter_caller::v1::InterpreterCallerMeta)
33        }
34        other => return Err(anyhow::anyhow!("Unsupported for {} meta", other)),
35    };
36    let schema_string = if s.pretty_print {
37        serde_json::to_string_pretty(&schema_json)?
38    } else {
39        serde_json::to_string(&schema_json)?
40    };
41
42    crate::cli::output::output(
43        &s.output_path,
44        SupportedOutputEncoding::Binary,
45        schema_string.as_bytes(),
46    )
47}
48
49#[cfg(all(test, not(target_family = "wasm")))]
50mod tests {
51    use super::*;
52
53    fn show_to_string(schema: KnownMeta, pretty_print: bool) -> anyhow::Result<String> {
54        let file = tempfile::NamedTempFile::new().unwrap();
55        let path = file.path().to_path_buf();
56        show(Show {
57            schema,
58            output_path: Some(path.clone()),
59            pretty_print,
60        })?;
61        Ok(std::fs::read_to_string(&path).unwrap())
62    }
63
64    /// Each supported meta produces its own schema; compact output by
65    /// default (no newlines).
66    #[test]
67    fn test_show_op_v1_schema_compact() {
68        let s = show_to_string(KnownMeta::OpV1, false).unwrap();
69        let v: serde_json::Value = serde_json::from_str(&s).unwrap();
70        assert_eq!(v["title"], "OpMeta.");
71        assert!(!s.contains('\n'));
72    }
73
74    /// The pretty flag pretty-prints the same schema.
75    #[test]
76    fn test_show_pretty_print() {
77        let s = show_to_string(KnownMeta::OpV1, true).unwrap();
78        assert!(s.starts_with("{\n"));
79        let v: serde_json::Value = serde_json::from_str(&s).unwrap();
80        assert_eq!(v["title"], "OpMeta.");
81    }
82
83    /// All four supported arms return the schema of their own meta type.
84    #[test]
85    fn test_show_supported_schemas_are_distinct() {
86        let op = show_to_string(KnownMeta::OpV1, false).unwrap();
87        assert!(op.contains("OpMeta"));
88        let authoring = show_to_string(KnownMeta::AuthoringMetaV1, false).unwrap();
89        assert!(authoring.contains("AuthoringMeta"));
90        let solidity = show_to_string(KnownMeta::SolidityAbiV2, false).unwrap();
91        assert!(solidity.contains("SolidityAbi"));
92        let caller = show_to_string(KnownMeta::InterpreterCallerMetaV1, false).unwrap();
93        assert!(caller.contains("InterpreterCallerMeta"));
94        for pair in [
95            (&op, &authoring),
96            (&op, &solidity),
97            (&op, &caller),
98            (&authoring, &solidity),
99            (&authoring, &caller),
100            (&solidity, &caller),
101        ] {
102            assert_ne!(pair.0, pair.1);
103        }
104    }
105
106    /// Metas without a JSON schema error with the exact unsupported
107    /// message.
108    #[test]
109    fn test_show_unsupported_meta_error() {
110        let file = tempfile::NamedTempFile::new().unwrap();
111        let err = show(Show {
112            schema: KnownMeta::DotrainV1,
113            output_path: Some(file.path().to_path_buf()),
114            pretty_print: false,
115        })
116        .unwrap_err();
117        assert_eq!(err.to_string(), "Unsupported for dotrain-v1 meta");
118    }
119}