pax-macro 0.39.1

Macros for Pax, used for showing Pax where to attach to Rust code
Documentation
use sailfish::TemplateOnce;

use serde_derive::Serialize;

#[derive(Serialize, Debug)]
pub struct StaticPropertyDefinition {
    pub scoped_resolvable_types: Vec<String>,
    pub root_scoped_resolvable_type: String,
    pub field_name: String,
    pub original_type: String,
    pub pascal_identifier: String,
    pub is_property_wrapped: bool,
    pub is_enum: bool,
}

#[derive(Serialize, Debug)]
pub struct EnumVariantDefinition {
    pub variant_name: String,
    pub variant_fields: Vec<StaticPropertyDefinition>,
}

pub enum InternalDefinitions {
    Struct(Vec<StaticPropertyDefinition>),
    Enum(Vec<EnumVariantDefinition>),
}

#[derive(TemplateOnce)]
#[template(path = "../templates/cartridge.stpl", escape = false)]
pub struct TemplateArgsCartridge {
    pub catalog: bool,
    pub web_entrypoint: String,
    pub root_path: String,
    pub initializer: String,
    pub cartridge_snippet: String,
    pub engine_import_path: String,
    pub build_config: TemplateBuildConfig,
}

#[derive(Clone, Copy, Debug, Serialize)]
pub struct TemplateBuildConfig {
    pub web: bool,
    pub macos: bool,
    pub ios: bool,
    pub ipados: bool,
    pub designtime: bool,
}

#[derive(TemplateOnce)]
#[template(path = "../templates/derive_pax.stpl", escape = false)]
pub struct TemplateArgsDerivePax {
    /// Modal properties
    pub cartridge: String,

    /// Shared properties
    pub internal_definitions: InternalDefinitions,
    pub pascal_identifier: String,
    pub is_custom_interpolatable: bool,
    pub is_custom_coercion_rules: bool,
    pub can_derive_identity_roundtrip: bool,
    pub _is_enum: bool,

    /// Used to specify a custom import prefix for codegen when importing
    /// `pax-engine` directly rather than through `pax-kit`.
    pub engine_import_path: String,
}

#[cfg(test)]
mod tests {
    use super::*;

    fn render_main(root: bool, target: &str, designtime: bool) -> String {
        TemplateArgsDerivePax {
            cartridge: if root {
                TemplateArgsCartridge {
                    catalog: false,
                    web_entrypoint: "init_web".into(),
                    root_path: "EmbeddedExample".into(),
                    initializer: "example_init".into(),
                    cartridge_snippet: "const CARTRIDGE_OWNER: bool = true;".into(),
                    engine_import_path: "pax_engine".into(),
                    build_config: TemplateBuildConfig {
                        web: target == "web",
                        macos: target == "macos",
                        ios: target == "ios",
                        ipados: target == "ipados",
                        designtime,
                    },
                }
                .render_once()
                .unwrap()
            } else {
                String::new()
            },
            internal_definitions: InternalDefinitions::Struct(vec![]),
            pascal_identifier: "EmbeddedExample".into(),
            is_custom_interpolatable: false,
            is_custom_coercion_rules: false,
            can_derive_identity_roundtrip: false,
            _is_enum: false,
            engine_import_path: "pax_engine".into(),
        }
        .render_once()
        .unwrap()
    }

    #[test]
    fn dependency_main_remains_a_component_without_platform_entrypoints() {
        for target in ["web", "macos", "ios", "ipados"] {
            for designtime in [true, false] {
                let generated = render_main(false, target, designtime);
                syn::parse_file(&generated).unwrap();
                assert!(generated.contains("Interpolatable for EmbeddedExample"));
                assert!(!generated.contains("CARTRIDGE_OWNER"));
                assert!(!generated.contains("fn pax_init"));
                assert!(!generated.contains("fn init_web"));
                assert!(!generated.contains("init_manifest"));
                assert!(!generated.contains("example_init"));
                assert!(!generated.contains("pub use pax_engine::pax_chassis"));
            }
        }
    }

    #[test]
    fn application_main_keeps_debug_and_release_entrypoints() {
        for target in ["web", "macos", "ios", "ipados"] {
            for designtime in [true, false] {
                let generated = render_main(true, target, designtime);
                syn::parse_file(&generated).unwrap();
                assert!(generated.contains("CARTRIDGE_OWNER"));
                assert_eq!(
                    generated
                        .matches(if target == "web" {
                            "fn init_web"
                        } else {
                            "fn pax_init("
                        })
                        .count(),
                    1
                );
                assert!(generated.contains("init_manifest"));
                assert!(generated.contains("application.initialize(example_init)"));
                let debug_constructor = if target == "web" {
                    "new_designtime"
                } else {
                    "new_with_designtime"
                };
                assert_eq!(generated.contains(debug_constructor), designtime);
            }
        }
    }
}