Skip to main content

cedar_policy_cli/command/
translate_schema.rs

1/*
2 * Copyright Cedar Contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use cedar_policy::SchemaFragment;
18use clap::Args;
19use miette::{IntoDiagnostic, Result};
20
21use crate::{read_from_file_or_stdin, CedarExitCode};
22
23/// The direction of translation
24#[derive(Debug, Clone, Copy, clap::ValueEnum)]
25pub enum SchemaTranslationDirection {
26    /// JSON -> Cedar schema syntax
27    JsonToCedar,
28    /// Cedar schema syntax -> JSON
29    CedarToJson,
30    /// Cedar schema syntax -> JSON with all types resolved to entity or common.
31    ///
32    /// In contrast to `cedar-to-json`, this option requires that every type
33    /// referenced in the schema is also defined.
34    CedarToJsonWithResolvedTypes,
35}
36
37#[derive(Args, Debug)]
38pub struct TranslateSchemaArgs {
39    /// The direction of translation,
40    #[arg(long)]
41    pub direction: SchemaTranslationDirection,
42    /// Filename to read the schema from.
43    /// If not provided, will default to reading stdin.
44    #[arg(short = 's', long = "schema", value_name = "FILE")]
45    pub input_file: Option<String>,
46}
47
48pub fn translate_schema(args: &TranslateSchemaArgs) -> CedarExitCode {
49    match translate_schema_inner(args) {
50        Ok(sf) => {
51            println!("{sf}");
52            CedarExitCode::Success
53        }
54        Err(err) => {
55            eprintln!("{err:?}");
56            CedarExitCode::Failure
57        }
58    }
59}
60
61fn translate_schema_inner(args: &TranslateSchemaArgs) -> Result<String> {
62    let translate = match args.direction {
63        SchemaTranslationDirection::JsonToCedar => translate_schema_to_cedar,
64        SchemaTranslationDirection::CedarToJson => translate_schema_to_json,
65        SchemaTranslationDirection::CedarToJsonWithResolvedTypes => {
66            translate_schema_to_json_with_resolved_types
67        }
68    };
69    read_from_file_or_stdin(args.input_file.as_ref(), "schema").and_then(translate)
70}
71
72fn translate_schema_to_cedar(json_src: impl AsRef<str>) -> Result<String> {
73    let fragment = SchemaFragment::from_json_str(json_src.as_ref())?;
74    let output = fragment.to_cedarschema()?;
75    Ok(output)
76}
77
78fn translate_schema_to_json(cedar_src: impl AsRef<str>) -> Result<String> {
79    let (fragment, warnings) = SchemaFragment::from_cedarschema_str(cedar_src.as_ref())?;
80    for warning in warnings {
81        let report = miette::Report::new(warning);
82        eprintln!("{report:?}");
83    }
84    let output = fragment.to_json_string()?;
85    Ok(output)
86}
87
88fn translate_schema_to_json_with_resolved_types(cedar_src: impl AsRef<str>) -> Result<String> {
89    match cedar_policy::schema_str_to_json_with_resolved_types(cedar_src.as_ref()) {
90        Ok((json_value, warnings)) => {
91            // Output warnings to stderr
92            for warning in &warnings {
93                eprintln!("{warning}");
94            }
95
96            // Serialize to JSON with pretty formatting
97            serde_json::to_string_pretty(&json_value).into_diagnostic()
98        }
99        Err(error) => {
100            // Convert CedarSchemaError to miette::Report to preserve all diagnostic information
101            Err(miette::Report::new(error))
102        }
103    }
104}