Skip to main content

cdk_from_cfn/
lib.rs

1#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
2
3use indexmap::IndexMap;
4use parser::condition::ConditionFunction;
5use parser::lookup_table::MappingTable;
6use parser::output::Output;
7use parser::parameters::Parameter;
8use parser::resource::ResourceAttributes;
9use serde::{Deserialize, Deserializer};
10
11pub mod cdk;
12pub mod code;
13pub mod errors;
14pub mod ir;
15pub mod parser;
16pub mod primitives;
17pub mod synthesizer;
18
19mod util;
20
21#[doc(inline)]
22pub use errors::*;
23
24#[doc(inline)]
25pub use util::Hasher;
26
27#[derive(Debug, serde::Deserialize)]
28#[serde(rename_all = "PascalCase")]
29pub struct CloudformationParseTree {
30    pub description: Option<String>,
31
32    #[serde(
33        default,
34        rename = "Transform",
35        deserialize_with = "string_or_seq_string"
36    )]
37    pub transforms: Vec<String>,
38
39    #[serde(default)]
40    pub conditions: IndexMap<String, ConditionFunction, Hasher>,
41    #[serde(default)]
42    pub mappings: IndexMap<String, MappingTable, Hasher>,
43    #[serde(default)]
44    pub outputs: IndexMap<String, Output, Hasher>,
45    #[serde(default)]
46    pub parameters: IndexMap<String, Parameter, Hasher>,
47
48    pub resources: IndexMap<String, ResourceAttributes, Hasher>,
49}
50
51fn string_or_seq_string<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
52where
53    D: Deserializer<'de>,
54{
55    #[derive(Deserialize)]
56    #[serde(untagged)]
57    pub enum Transform<'a> {
58        String(&'a str),
59        Vec(Vec<String>),
60    }
61
62    Ok(match Transform::deserialize(deserializer)? {
63        Transform::String(transform) => vec![transform.to_owned()],
64        Transform::Vec(transform) => transform,
65    })
66}
67
68#[cfg(target_family = "wasm")]
69pub mod wasm {
70    use std::borrow::Cow;
71
72    use cdk::Schema;
73    use wasm_bindgen::prelude::*;
74
75    use super::*;
76
77    /// Returns an array containing all supported language names.
78    #[wasm_bindgen]
79    pub fn supported_languages() -> Box<[JsValue]> {
80        vec![
81            #[cfg(feature = "typescript")]
82            wasm_bindgen::intern("typescript").into(),
83            #[cfg(feature = "golang")]
84            wasm_bindgen::intern("go").into(),
85            #[cfg(feature = "java")]
86            wasm_bindgen::intern("java").into(),
87            #[cfg(feature = "python")]
88            wasm_bindgen::intern("python").into(),
89            #[cfg(feature = "csharp")]
90            wasm_bindgen::intern("csharp").into(),
91        ]
92        .into_boxed_slice()
93    }
94
95    /// Transforms the provided template into a CDK application in the specified
96    /// language.
97    #[wasm_bindgen]
98    pub fn transmute(template: &str, language: &str, stack_name: &str) -> Result<String, JsError> {
99        let cfn_tree: CloudformationParseTree = serde_yaml::from_str(template)?;
100        let schema = Cow::Borrowed(Schema::builtin());
101        let ir = crate::ir::CloudformationProgramIr::from(cfn_tree, &schema)?;
102        let mut output = Vec::new();
103
104        let synthesizer: Box<dyn crate::synthesizer::Synthesizer> = match language {
105            #[cfg(feature = "typescript")]
106            "typescript" => Box::new(crate::synthesizer::Typescript {}),
107            #[cfg(feature = "golang")]
108            "go" => Box::<crate::synthesizer::Golang>::default(),
109            #[cfg(feature = "python")]
110            "python" => Box::new(crate::synthesizer::Python {}),
111            #[cfg(feature = "java")]
112            "java" => Box::<crate::synthesizer::Java>::default(),
113            #[cfg(feature = "csharp")]
114            "csharp" => Box::<crate::synthesizer::CSharp>::default(),
115            unsupported => {
116                return Err(JsError::from(Error::UnsupportedLanguageError {
117                    language: unsupported.to_string(),
118                }));
119            }
120        };
121
122        ir.synthesize(synthesizer.as_ref(), &mut output, stack_name)?;
123
124        String::from_utf8(output).map_err(Into::into)
125    }
126
127    #[cfg(feature = "console_error_panic_hook")]
128    #[wasm_bindgen(start)]
129    fn wasm_init() {
130        console_error_panic_hook::set_once();
131    }
132}