Skip to main content

tsz_common/
checker_options.rs

1//! Compiler options for type checking.
2//!
3//! This module lives in tsz-common so that both the solver and checker
4//! can reference `CheckerOptions` without creating a circular dependency.
5
6use crate::common::{ModuleKind, ScriptTarget};
7
8/// Compiler options for type checking.
9#[derive(Debug, Clone)]
10pub struct CheckerOptions {
11    pub strict: bool,
12    pub no_implicit_any: bool,
13    pub no_implicit_returns: bool,
14    pub strict_null_checks: bool,
15    pub strict_function_types: bool,
16    pub strict_property_initialization: bool,
17    pub no_implicit_this: bool,
18    pub use_unknown_in_catch_variables: bool,
19    pub isolated_modules: bool,
20    /// When true, indexed access with index signatures adds `| undefined` to the type
21    pub no_unchecked_indexed_access: bool,
22    /// When true, checking bind/call/apply uses strict function signatures
23    pub strict_bind_call_apply: bool,
24    /// When true, optional properties are treated as exactly `T | undefined` not `T | undefined | missing`
25    pub exact_optional_property_types: bool,
26    /// When true, no library files (including lib.d.ts) are included.
27    /// This corresponds to the --noLib compiler flag.
28    /// TS2318 errors are emitted when referencing global types with this option enabled.
29    pub no_lib: bool,
30    /// When true, do not automatically inject built-in type declarations.
31    /// This corresponds to the --noTypesAndSymbols compiler flag.
32    /// Prevents loading default lib.d.ts files which provide types like Array, Object, etc.
33    pub no_types_and_symbols: bool,
34    /// Target ECMAScript version (ES3, ES5, ES2015, ES2016, etc.)
35    /// Controls which built-in types are available (e.g., Promise requires ES2015)
36    /// Defaults to ES3 for maximum compatibility
37    pub target: ScriptTarget,
38    /// Module kind (None, `CommonJS`, ES2015, ES2020, ES2022, `ESNext`, etc.)
39    /// Controls which module system is being targeted (affects import/export syntax validity)
40    pub module: ModuleKind,
41    /// Emit additional JavaScript to ease support for importing `CommonJS` modules.
42    /// When true, synthesizes default exports for `CommonJS` modules.
43    pub es_module_interop: bool,
44    /// Allow 'import x from y' when a module doesn't have a default export.
45    /// Implied by esModuleInterop.
46    pub allow_synthetic_default_imports: bool,
47    /// Controls reporting of unreachable code (TS7027).
48    /// - `None` (default): tsc emits TS7027 as a suggestion, not an error
49    /// - `Some(false)`: tsc emits TS7027 as an error
50    /// - `Some(true)`: tsc does not emit TS7027 at all
51    pub allow_unreachable_code: Option<bool>,
52    /// When true, require bracket notation for index signature property access (TS4111).
53    pub no_property_access_from_index_signature: bool,
54    /// When true, enable Sound Mode for stricter type checking beyond TypeScript's defaults.
55    /// Sound Mode catches common unsoundness issues like:
56    /// - Mutable array covariance (TS9002)
57    /// - Method parameter bivariance (TS9003)
58    /// - `any` escapes (TS9004)
59    /// - Excess properties via sticky freshness (TS9001)
60    ///
61    /// Activated via: `--sound` CLI flag or `// @ts-sound` pragma
62    pub sound_mode: bool,
63    /// When true, enables experimental support for decorators (legacy decorators).
64    /// This is required for the @experimentalDecorators flag.
65    /// When decorators are used, `TypedPropertyDescriptor` must be available.
66    pub experimental_decorators: bool,
67    /// When true, report errors for unused local variables (TS6133).
68    pub no_unused_locals: bool,
69    /// When true, report errors for unused function parameters (TS6133).
70    pub no_unused_parameters: bool,
71    /// When true, parse in strict mode and emit "use strict" for each source file.
72    /// Enables TS1100 for invalid use of 'arguments' in strict mode.
73    pub always_strict: bool,
74    /// When true, allows importing JSON files with `.json` extension.
75    /// When false, importing JSON files emits TS2732 suggesting to enable this flag.
76    pub resolve_json_module: bool,
77    /// When true, enable type checking in JavaScript files.
78    /// This corresponds to the --checkJs compiler flag.
79    /// With checkJs enabled, noImplicitAny and other type errors apply to .js files.
80    pub check_js: bool,
81    /// When true, disable dependency expansion from imports and triple-slash references.
82    pub no_resolve: bool,
83    /// When true, check side-effect imports for module resolution errors (TS2882).
84    pub no_unchecked_side_effect_imports: bool,
85    /// When true, require 'override' modifier on members that override base class members (TS4114).
86    pub no_implicit_override: bool,
87    /// JSX factory function (e.g. `React.createElement`)
88    pub jsx_factory: String,
89    /// JSX fragment factory function (e.g. `React.Fragment`)
90    pub jsx_fragment_factory: String,
91    /// JSX emit mode (preserve, react, react-jsx, react-jsxdev, react-native).
92    /// Only "react" (classic transform) requires the factory to be in scope.
93    pub jsx_mode: JsxMode,
94}
95
96/// JSX emit mode controlling how JSX is transformed.
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
98pub enum JsxMode {
99    /// No JSX mode specified (default — treated same as None/no JSX).
100    #[default]
101    None,
102    /// Keep JSX as-is in the output (no factory required in scope).
103    Preserve,
104    /// Classic React transform — requires factory (e.g. `React.createElement`) in scope.
105    React,
106    /// Automatic React transform via `_jsx` — factory NOT required in scope.
107    ReactJsx,
108    /// Development automatic React transform — factory NOT required in scope.
109    ReactJsxDev,
110    /// React Native — preserve JSX (no factory required in scope).
111    ReactNative,
112}
113
114impl Default for CheckerOptions {
115    fn default() -> Self {
116        Self {
117            strict: true,
118            no_implicit_any: true,
119            no_implicit_returns: false,
120            strict_null_checks: true,
121            strict_function_types: true,
122            strict_property_initialization: true,
123            no_implicit_this: true,
124            use_unknown_in_catch_variables: true,
125            isolated_modules: false,
126            no_unchecked_indexed_access: false,
127            strict_bind_call_apply: true,
128            exact_optional_property_types: false,
129            no_lib: false,
130            no_types_and_symbols: false,
131            target: ScriptTarget::default(),
132            module: ModuleKind::default(),
133            es_module_interop: false,
134            allow_synthetic_default_imports: false,
135            allow_unreachable_code: None,
136            no_property_access_from_index_signature: false,
137            sound_mode: false,
138            experimental_decorators: false,
139            no_unused_locals: false,
140            no_unused_parameters: false,
141            // TSC 6.0 defaults: `alwaysStrict !== false` → true when not explicitly set.
142            // This matches TypeScript's behavior where alwaysStrict is true by default.
143            always_strict: true,
144            resolve_json_module: false,
145            check_js: false,
146            no_resolve: false,
147            no_unchecked_side_effect_imports: true,
148            no_implicit_override: false,
149            jsx_factory: "React.createElement".to_string(),
150            jsx_fragment_factory: "React.Fragment".to_string(),
151            jsx_mode: JsxMode::None,
152        }
153    }
154}
155
156impl CheckerOptions {
157    /// Apply TypeScript's `--strict` defaults to individual strict flags.
158    /// In tsc, enabling `strict` turns on the strict family unless explicitly disabled.
159    /// We mirror that behavior by OR-ing the per-flag booleans with `strict`.
160    #[must_use]
161    pub const fn apply_strict_defaults(mut self) -> Self {
162        if self.strict {
163            self.no_implicit_any = true;
164            self.no_implicit_this = true;
165            self.strict_null_checks = true;
166            self.strict_function_types = true;
167            self.strict_bind_call_apply = true;
168            self.strict_property_initialization = true;
169            self.use_unknown_in_catch_variables = true;
170            self.always_strict = true;
171            // exactOptionalPropertyTypes and other opts are not implied by --strict
172        }
173        self
174    }
175}