Skip to main content

stylex_compiler_rs/structs/
mod.rs

1use napi::{JsObject, UnknownRef};
2use napi_derive::napi;
3use rustc_hash::FxHashMap;
4use stylex_enums::{
5  property_validation_mode::PropertyValidationMode as StylexPropertyValidationMode,
6  style_resolution::StyleResolution, sx_prop_name_param::SxPropNameParam,
7};
8use stylex_structures::{
9  named_import_source::{ImportSources, NamedImportSource, RuntimeInjection},
10  stylex_options::{ModuleResolution, StyleXOptionsParams},
11};
12
13use crate::enums::{
14  ImportSourceUnion, PropertyValidationMode, RuntimeInjectionUnion, SourceMaps,
15  StyleXModuleResolution, SxPropNameUnion,
16};
17
18#[napi(object)]
19pub struct StyleXOptions {
20  #[napi(ts_type = "'application-order' | 'property-specificity' | 'legacy-expand-shorthands'")]
21  pub style_resolution: Option<String>,
22  pub enable_font_size_px_to_rem: Option<bool>,
23  #[napi(ts_type = "boolean | string")]
24  pub runtime_injection: Option<RuntimeInjectionUnion>,
25  pub class_name_prefix: Option<String>,
26  #[napi(ts_type = "Record<string, string>")]
27  pub defined_stylex_css_variables: Option<FxHashMap<String, String>>,
28  #[napi(ts_type = "(string | { as: string, from: string })[]")]
29  pub import_sources: Option<Vec<ImportSourceUnion>>,
30  pub treeshake_compensation: Option<bool>,
31  pub enable_inlined_conditional_merge: Option<bool>,
32  pub enable_media_query_order: Option<bool>,
33  pub enable_logical_styles_polyfill: Option<bool>,
34  pub enable_legacy_value_flipping: Option<bool>,
35  #[napi(js_name = "enableLTRRTLComments")]
36  pub enable_ltr_rtl_comments: Option<bool>,
37  pub legacy_disable_layers: Option<bool>,
38  pub dev: Option<bool>,
39  pub test: Option<bool>,
40  pub debug: Option<bool>,
41  pub enable_debug_class_names: Option<bool>,
42  pub enable_debug_data_prop: Option<bool>,
43  pub enable_dev_class_names: Option<bool>,
44  pub enable_minified_keys: Option<bool>,
45  pub inject_stylex_side_effects: Option<bool>,
46  pub use_real_file_for_source: Option<bool>,
47  #[napi(ts_type = "Record<string, string[]>")]
48  pub aliases: Option<FxHashMap<String, Vec<String>>>,
49  #[napi(js_name = "unstable_moduleResolution")]
50  pub unstable_module_resolution: Option<StyleXModuleResolution>,
51  pub source_map: Option<SourceMaps>,
52  #[napi(ts_type = "Array<string | RegExp>")]
53  pub include: Option<Vec<UnknownRef>>,
54  #[napi(ts_type = "Array<string | RegExp>")]
55  pub exclude: Option<Vec<UnknownRef>>,
56  #[napi(ts_type = "Array<[string, Record<string, any>]>")]
57  pub swc_plugins: Option<Vec<UnknownRef>>,
58  #[napi(ts_type = "'throw' | 'warn' | 'silent'")]
59  pub property_validation_mode: Option<PropertyValidationMode>,
60  /// Compile-time constants and functions accessible via `stylex.env`.
61  #[napi(ts_type = "Record<string, any>")]
62  pub env: Option<JsObject>,
63  /// Optional function or string to transform file paths used in debug class names / source maps.
64  #[napi(ts_type = "((filePath: string) => string) | string | undefined")]
65  pub debug_file_path: Option<napi::UnknownRef>,
66  /// The prop name to use as the `sx` shorthand (default: `"sx"`). Set to `false` to disable.
67  #[napi(ts_type = "string | false")]
68  pub sx_prop_name: Option<SxPropNameUnion>,
69}
70
71#[napi(object)]
72pub struct StyleXMetadata {
73  #[napi(ts_type = "([string, { ltr: string; rtl?: null | string }, number])[]")]
74  pub stylex: Vec<JsObject>,
75}
76
77#[napi(object)]
78pub struct StyleXTransformResult {
79  pub code: String,
80  pub metadata: StyleXMetadata,
81  pub map: Option<String>,
82}
83
84impl TryFrom<StyleXOptions> for StyleXOptionsParams {
85  type Error = napi::Error;
86  fn try_from(val: StyleXOptions) -> Result<Self, Self::Error> {
87    let style_resolution: Option<StyleResolution> = val
88      .style_resolution
89      .map(|sr| {
90        serde_plain::from_str(&sr)
91          .map_err(|e| napi::Error::from_reason(format!("Failed to parse style resolution: {}", e)))
92      })
93      .transpose()?;
94
95    let import_sources: Option<Vec<ImportSources>> = val.import_sources.map(|import_sources| {
96      import_sources
97        .into_iter()
98        .map(|source| match source {
99          ImportSourceUnion::Regular(s) => ImportSources::Regular(s),
100          ImportSourceUnion::Named(named) => ImportSources::Named(NamedImportSource {
101            r#as: named.r#as,
102            from: named.from,
103          }),
104        })
105        .collect()
106    });
107
108    let unstable_module_resolution = val.unstable_module_resolution.map(|res| ModuleResolution {
109      r#type: res.r#type,
110      root_dir: res.root_dir,
111      theme_file_extension: res.theme_file_extension,
112    });
113
114    let runtime_injection: Option<RuntimeInjection> = val.runtime_injection.map(|ri| match ri {
115      RuntimeInjectionUnion::Boolean(b) => RuntimeInjection::Boolean(b),
116      RuntimeInjectionUnion::Regular(s) => RuntimeInjection::Regular(s),
117    });
118
119    let property_validation_mode: Option<StylexPropertyValidationMode> =
120      val.property_validation_mode.map(|pvm| match pvm {
121        PropertyValidationMode::Throw => StylexPropertyValidationMode::Throw,
122        PropertyValidationMode::Warn => StylexPropertyValidationMode::Warn,
123        PropertyValidationMode::Silent => StylexPropertyValidationMode::Silent,
124      });
125
126    let sx_prop_name: Option<SxPropNameParam> = val.sx_prop_name.map(|spn| match spn {
127      SxPropNameUnion::Disabled => SxPropNameParam::Disabled,
128      SxPropNameUnion::Name(s) => SxPropNameParam::Enabled(s),
129    });
130
131    Ok(StyleXOptionsParams {
132      style_resolution,
133      enable_font_size_px_to_rem: val.enable_font_size_px_to_rem,
134      runtime_injection,
135      class_name_prefix: val.class_name_prefix,
136      defined_stylex_css_variables: val.defined_stylex_css_variables,
137      import_sources,
138      treeshake_compensation: val.treeshake_compensation,
139      enable_inlined_conditional_merge: val.enable_inlined_conditional_merge,
140      enable_media_query_order: val.enable_media_query_order,
141      enable_logical_styles_polyfill: val.enable_logical_styles_polyfill,
142      enable_legacy_value_flipping: val.enable_legacy_value_flipping,
143      enable_ltr_rtl_comments: val.enable_ltr_rtl_comments,
144      use_real_file_for_source: val.use_real_file_for_source,
145      dev: val.dev,
146      test: val.test,
147      debug: val.debug.or(val.dev),
148      enable_debug_class_names: val.enable_debug_class_names,
149      enable_debug_data_prop: val.enable_debug_data_prop,
150      enable_dev_class_names: val.enable_dev_class_names,
151      enable_minified_keys: val.enable_minified_keys,
152      inject_stylex_side_effects: val.inject_stylex_side_effects,
153      aliases: val.aliases,
154      unstable_module_resolution,
155      sx_prop_name,
156      property_validation_mode,
157      env: None, // Parsed separately via parse_env_object since it needs napi::Env
158      debug_file_path: None, // Parsed separately via parse_debug_file_path since it needs napi::Env
159    })
160  }
161}