Skip to main content

react_compiler_hir/
environment_config.rs

1// Copyright (c) Meta Platforms, Inc. and affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6//! Environment configuration, ported from EnvironmentConfigSchema in Environment.ts.
7//!
8//! Contains feature flags and custom hook definitions that control compiler behavior.
9
10use std::collections::HashMap;
11
12use serde::{Deserialize, Serialize};
13
14use crate::type_config::{TypeConfig, ValueKind};
15use crate::Effect;
16
17/// External function reference (source module + import name).
18/// Corresponds to TS `ExternalFunction`.
19#[derive(Debug, Clone, Serialize, Deserialize)]
20#[serde(rename_all = "camelCase")]
21pub struct ExternalFunctionConfig {
22    pub source: String,
23    pub import_specifier_name: String,
24}
25
26/// Instrumentation configuration.
27/// Corresponds to TS `InstrumentationSchema`.
28#[derive(Debug, Clone, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct InstrumentationConfig {
31    #[serde(rename = "fn")]
32    pub fn_: ExternalFunctionConfig,
33    #[serde(default)]
34    pub gating: Option<ExternalFunctionConfig>,
35    #[serde(default)]
36    pub global_gating: Option<String>,
37}
38
39/// Custom hook configuration, ported from TS `HookSchema`.
40#[derive(Debug, Clone, Serialize, Deserialize)]
41#[serde(rename_all = "camelCase")]
42pub struct HookConfig {
43    pub effect_kind: Effect,
44    pub value_kind: ValueKind,
45    #[serde(default)]
46    pub no_alias: bool,
47    #[serde(default)]
48    pub transitive_mixed_data: bool,
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
52pub enum ExhaustiveEffectDepsMode {
53    #[serde(rename = "off")]
54    Off,
55    #[serde(rename = "all")]
56    All,
57    #[serde(rename = "missing-only")]
58    MissingOnly,
59    #[serde(rename = "extra-only")]
60    ExtraOnly,
61}
62
63impl Default for ExhaustiveEffectDepsMode {
64    fn default() -> Self {
65        Self::Off
66    }
67}
68
69fn default_true() -> bool {
70    true
71}
72
73/// Compiler environment configuration. Contains feature flags and settings.
74///
75/// Fields that would require passing JS functions across the JS/Rust boundary
76/// are omitted with TODO comments. The Rust port uses hardcoded defaults for
77/// these (e.g., `defaultModuleTypeProvider`).
78#[derive(Debug, Clone, Serialize, Deserialize)]
79#[serde(rename_all = "camelCase")]
80pub struct EnvironmentConfig {
81    /// Custom hook type definitions, keyed by hook name.
82    #[serde(default)]
83    pub custom_hooks: HashMap<String, HookConfig>,
84
85    /// Pre-resolved module type provider results.
86    /// Map from module name to TypeConfig, computed by the JS shim.
87    #[serde(default)]
88    pub module_type_provider: Option<indexmap::IndexMap<String, TypeConfig>>,
89
90    /// Custom macro-like function names that should have their operands
91    /// memoized in the same scope (similar to fbt).
92    #[serde(default)]
93    pub custom_macros: Option<Vec<String>>,
94
95    /// If true, emit code to reset the memo cache on source file changes (HMR/fast refresh).
96    /// If null (None), HMR detection is conditionally enabled based on NODE_ENV/__DEV__.
97    #[serde(default)]
98    pub enable_reset_cache_on_source_file_changes: Option<bool>,
99
100    #[serde(default = "default_true")]
101    pub enable_preserve_existing_memoization_guarantees: bool,
102    #[serde(default = "default_true")]
103    pub validate_preserve_existing_memoization_guarantees: bool,
104    #[serde(default = "default_true")]
105    pub validate_exhaustive_memoization_dependencies: bool,
106    #[serde(default)]
107    pub validate_exhaustive_effect_dependencies: ExhaustiveEffectDepsMode,
108
109    // TODO: flowTypeProvider — requires JS function callback.
110
111    #[serde(default = "default_true")]
112    pub enable_optional_dependencies: bool,
113    #[serde(default)]
114    pub enable_name_anonymous_functions: bool,
115    #[serde(default = "default_true")]
116    pub validate_hooks_usage: bool,
117    #[serde(default = "default_true")]
118    pub validate_ref_access_during_render: bool,
119    #[serde(default = "default_true")]
120    pub validate_no_set_state_in_render: bool,
121    #[serde(default)]
122    pub enable_use_keyed_state: bool,
123    #[serde(default)]
124    pub validate_no_set_state_in_effects: bool,
125    #[serde(default)]
126    pub validate_no_derived_computations_in_effects: bool,
127    #[serde(default)]
128    #[serde(alias = "validateNoDerivedComputationsInEffects_exp")]
129    pub validate_no_derived_computations_in_effects_exp: bool,
130    #[serde(default)]
131    #[serde(alias = "validateNoJSXInTryStatements")]
132    pub validate_no_jsx_in_try_statements: bool,
133    #[serde(default)]
134    pub validate_static_components: bool,
135    #[serde(default)]
136    pub validate_no_capitalized_calls: Option<Vec<String>>,
137    #[serde(default)]
138    #[serde(alias = "restrictedImports")]
139    pub validate_blocklisted_imports: Option<Vec<String>>,
140    #[serde(default)]
141    pub validate_source_locations: bool,
142    #[serde(default)]
143    pub validate_no_impure_functions_in_render: bool,
144    #[serde(default)]
145    pub validate_no_freezing_known_mutable_functions: bool,
146    #[serde(default = "default_true")]
147    pub enable_assume_hooks_follow_rules_of_react: bool,
148    #[serde(default = "default_true")]
149    pub enable_transitively_freeze_function_expressions: bool,
150
151    /// Hook guard configuration. When set, wraps hook calls with dispatcher guard calls.
152    #[serde(default)]
153    pub enable_emit_hook_guards: Option<ExternalFunctionConfig>,
154
155    /// Instrumentation configuration. When set, emits calls to instrument functions.
156    #[serde(default)]
157    pub enable_emit_instrument_forget: Option<InstrumentationConfig>,
158
159    #[serde(default = "default_true")]
160    pub enable_function_outlining: bool,
161    #[serde(default)]
162    pub enable_jsx_outlining: bool,
163    #[serde(default)]
164    pub assert_valid_mutable_ranges: bool,
165    #[serde(default)]
166    #[serde(alias = "throwUnknownException__testonly")]
167    pub throw_unknown_exception_testonly: bool,
168    #[serde(default)]
169    pub enable_custom_type_definition_for_reanimated: bool,
170    #[serde(default = "default_true")]
171    pub enable_treat_ref_like_identifiers_as_refs: bool,
172    #[serde(default)]
173    pub enable_treat_set_identifiers_as_state_setters: bool,
174    #[serde(default = "default_true")]
175    pub validate_no_void_use_memo: bool,
176    #[serde(default = "default_true")]
177    pub enable_allow_set_state_from_refs_in_effects: bool,
178    #[serde(default)]
179    pub enable_verbose_no_set_state_in_effect: bool,
180
181    // 🌲
182    #[serde(default)]
183    pub enable_forest: bool,
184}
185
186impl Default for EnvironmentConfig {
187    fn default() -> Self {
188        Self {
189            custom_hooks: HashMap::new(),
190            enable_reset_cache_on_source_file_changes: None,
191            module_type_provider: None,
192            enable_preserve_existing_memoization_guarantees: true,
193            validate_preserve_existing_memoization_guarantees: true,
194            validate_exhaustive_memoization_dependencies: true,
195            validate_exhaustive_effect_dependencies: ExhaustiveEffectDepsMode::Off,
196            enable_optional_dependencies: true,
197            enable_name_anonymous_functions: false,
198            validate_hooks_usage: true,
199            validate_ref_access_during_render: true,
200            validate_no_set_state_in_render: true,
201            enable_use_keyed_state: false,
202            validate_no_set_state_in_effects: false,
203            validate_no_derived_computations_in_effects: false,
204            validate_no_derived_computations_in_effects_exp: false,
205            validate_no_jsx_in_try_statements: false,
206            validate_static_components: false,
207            validate_no_capitalized_calls: None,
208            validate_blocklisted_imports: None,
209            validate_source_locations: false,
210            validate_no_impure_functions_in_render: false,
211            validate_no_freezing_known_mutable_functions: false,
212            enable_assume_hooks_follow_rules_of_react: true,
213            enable_transitively_freeze_function_expressions: true,
214            enable_emit_hook_guards: None,
215            enable_emit_instrument_forget: None,
216            enable_function_outlining: true,
217            enable_jsx_outlining: false,
218            assert_valid_mutable_ranges: false,
219            throw_unknown_exception_testonly: false,
220            enable_custom_type_definition_for_reanimated: false,
221            enable_treat_ref_like_identifiers_as_refs: true,
222            enable_treat_set_identifiers_as_state_setters: false,
223            validate_no_void_use_memo: true,
224            enable_allow_set_state_from_refs_in_effects: true,
225            enable_verbose_no_set_state_in_effect: false,
226            enable_forest: false,
227            custom_macros: None,
228        }
229    }
230}