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 #[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 #[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}