vize_atelier_sfc 0.46.0

Atelier SFC - The Single File Component workshop for Vize
Documentation
//! Script compilation for Vue SFCs.
//!
//! This module handles compilation of `<script>` and `<script setup>` blocks,
//! following the Vue.js core output format.

pub mod function_mode;
pub mod import_utils;
pub mod inline;
pub mod macros;
pub mod props;
pub mod statement_sections;
#[cfg(test)]
mod tests;
pub mod typescript;

use crate::types::{BindingMetadata, ScriptCompileOptions, SfcDescriptor, SfcError};

use self::function_mode::compile_script_setup;
use self::typescript::transform_typescript_to_js;

// Re-export commonly used items
pub use self::function_mode::compile_script_setup as compile_script_setup_function_mode;
pub use self::import_utils::{extract_import_identifiers, process_import_for_types};
pub use self::inline::compile_script_setup_inline;
pub(crate) use self::inline::compile_script_setup_inline_with_context;
pub use self::macros::{
    is_macro_call_line, is_multiline_macro_start, is_paren_macro_start, is_props_destructure_line,
};
pub use self::props::{
    extract_emit_names_from_type, extract_prop_types_from_type, extract_with_defaults_defaults,
    is_valid_identifier, PropTypeInfo,
};
use vize_carton::{String, ToCompactString};

/// Script compilation result
pub struct ScriptCompileResult {
    pub code: String,
    pub bindings: Option<BindingMetadata>,
}

/// Template parts for inline compilation
pub struct TemplateParts<'a> {
    pub imports: &'a str,
    pub hoisted: &'a str,
    pub render_fn: &'a str,
    pub render_fn_name: &'a str,
    /// Component/directive resolution statements (inside render function, before return)
    pub preamble: &'a str,
    pub render_body: &'a str,
    /// Whether render_body contains a full statement block instead of a return expression
    pub render_is_block: bool,
}

/// Compile script block(s)
#[allow(dead_code)]
pub fn compile_script(
    descriptor: &SfcDescriptor,
    _options: &ScriptCompileOptions,
    component_name: &str,
    is_vapor: bool,
    is_ts: bool,
) -> Result<ScriptCompileResult, SfcError> {
    // Handle script setup
    if let Some(script_setup) = &descriptor.script_setup {
        let template_content = descriptor.template.as_ref().map(|t| t.content.as_ref());
        compile_script_setup(
            &script_setup.content,
            component_name,
            is_vapor,
            is_ts,
            template_content,
        )
    } else if let Some(script) = &descriptor.script {
        // Use regular script, wrapped in __sfc__
        let mut code = String::default();
        code.push_str(&script.content);
        if is_vapor {
            code.push_str("\nconst __sfc__ = { ...(__default__ || {}), __vapor: true }\n");
        } else {
            code.push_str("\nconst __sfc__ = __default__\n");
        }
        // Transform TypeScript to JavaScript only when output is not TS.
        let final_code = if is_ts {
            code
        } else {
            transform_typescript_to_js(&code)
        };
        Ok(ScriptCompileResult {
            code: final_code,
            bindings: None,
        })
    } else {
        // No script - generate empty component
        if is_vapor {
            Ok(ScriptCompileResult {
                code: "const __sfc__ = { __vapor: true }\n".to_compact_string(),
                bindings: None,
            })
        } else {
            Ok(ScriptCompileResult {
                code: "const __sfc__ = {}\n".to_compact_string(),
                bindings: None,
            })
        }
    }
}