Skip to main content

tsz_common/
common.rs

1//! Common types and constants for the compiler
2//!
3//! This module contains shared types used across multiple compiler phases
4//! (parser, checker, emitter, transforms) to avoid circular dependencies.
5//!
6//! # Architecture
7//!
8//! By placing common types here, we establish a clear dependency hierarchy:
9//!
10//! ```text
11//! common (base layer)
12//!   ↓
13//! lowering_pass → transform_context → transforms → emitter
14//! ```
15//!
16//! No module should depend on a module that appears later in this chain.
17
18/// ECMAScript target version.
19///
20/// This determines which language features are available during compilation.
21#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
22#[repr(u8)]
23pub enum ScriptTarget {
24    /// ECMAScript 3 (1999)
25    ES3 = 0,
26
27    /// ECMAScript 5 (2009)
28    ES5 = 1,
29
30    /// ECMAScript 2015 (6th Edition)
31    ES2015 = 2,
32
33    /// ECMAScript 2016 (7th Edition)
34    ES2016 = 3,
35
36    /// ECMAScript 2017 (8th Edition)
37    ES2017 = 4,
38
39    /// ECMAScript 2018 (9th Edition)
40    ES2018 = 5,
41
42    /// ECMAScript 2019 (10th Edition)
43    ES2019 = 6,
44
45    /// ECMAScript 2020 (11th Edition)
46    ES2020 = 7,
47
48    /// ECMAScript 2021 (12th Edition)
49    ES2021 = 8,
50
51    /// ECMAScript 2022 (13th Edition)
52    ES2022 = 9,
53
54    /// ECMAScript 2023 (14th Edition)
55    ES2023 = 10,
56
57    /// ECMAScript 2024 (15th Edition)
58    ES2024 = 11,
59
60    /// ECMAScript 2025 (16th Edition) — TS6 default (`LatestStandard`)
61    ES2025 = 12,
62
63    /// Latest ECMAScript features
64    #[default]
65    ESNext = 99,
66}
67
68impl ScriptTarget {
69    /// Check if this target supports ES2016+ features (exponentiation operator).
70    #[must_use]
71    pub const fn supports_es2016(self) -> bool {
72        (self as u8) >= (Self::ES2016 as u8)
73    }
74
75    /// Check if this target supports ES2015+ features (classes, arrows, etc.)
76    #[must_use]
77    pub const fn supports_es2015(self) -> bool {
78        (self as u8) >= (Self::ES2015 as u8)
79    }
80
81    /// Check if this target supports ES2017+ features (async, etc.)
82    #[must_use]
83    pub const fn supports_es2017(self) -> bool {
84        (self as u8) >= (Self::ES2017 as u8)
85    }
86
87    /// Check if this target supports ES2020+ features (optional chaining, etc.)
88    #[must_use]
89    pub const fn supports_es2020(self) -> bool {
90        (self as u8) >= (Self::ES2020 as u8)
91    }
92
93    /// Check if this target supports ES2018+ features (async generators, dotAll regex, etc.)
94    #[must_use]
95    pub const fn supports_es2018(self) -> bool {
96        (self as u8) >= (Self::ES2018 as u8)
97    }
98
99    /// Check if this target supports ES2019+ features (optional catch binding).
100    #[must_use]
101    pub const fn supports_es2019(self) -> bool {
102        (self as u8) >= (Self::ES2019 as u8)
103    }
104
105    /// Check if this target supports ES2021+ features (logical assignment).
106    #[must_use]
107    pub const fn supports_es2021(self) -> bool {
108        (self as u8) >= (Self::ES2021 as u8)
109    }
110
111    /// Check if this target supports ES2022+ features (class fields, regex 'd' flag, etc.)
112    #[must_use]
113    pub const fn supports_es2022(self) -> bool {
114        (self as u8) >= (Self::ES2022 as u8)
115    }
116
117    /// Check if this target supports ES2023+ features.
118    #[must_use]
119    pub const fn supports_es2023(self) -> bool {
120        (self as u8) >= (Self::ES2023 as u8)
121    }
122
123    /// Check if this target supports ES2024+ features.
124    #[must_use]
125    pub const fn supports_es2024(self) -> bool {
126        (self as u8) >= (Self::ES2024 as u8)
127    }
128
129    /// Check if this target supports ES2025+ features.
130    #[must_use]
131    pub const fn supports_es2025(self) -> bool {
132        (self as u8) >= (Self::ES2025 as u8)
133    }
134
135    /// Check if this is an ES5 or earlier target (requires downleveling)
136    #[must_use]
137    pub const fn is_es5(self) -> bool {
138        (self as u8) <= (Self::ES5 as u8)
139    }
140}
141
142/// Module system kind.
143///
144/// Determines how modules are resolved and emitted in the output.
145#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
146#[repr(u8)]
147pub enum ModuleKind {
148    /// No module system (script mode)
149    #[default]
150    None = 0,
151
152    /// `CommonJS` (Node.js style)
153    CommonJS = 1,
154
155    /// Asynchronous Module Definition (`RequireJS` style)
156    AMD = 2,
157
158    /// Universal Module Definition
159    UMD = 3,
160
161    /// `SystemJS`
162    System = 4,
163
164    /// ES2015 modules (import/export)
165    ES2015 = 5,
166
167    /// ES2020 modules with dynamic `import()`
168    ES2020 = 6,
169
170    /// ES2022 modules with top-level await
171    ES2022 = 7,
172
173    /// Latest module features
174    ESNext = 99,
175
176    /// Node.js ESM (package.json "type": "module")
177    Node16 = 100,
178
179    /// Node.js with automatic detection
180    NodeNext = 199,
181
182    /// Preserve original import/export syntax (let bundler handle it)
183    Preserve = 200,
184}
185
186impl ModuleKind {
187    /// Check if this is a CommonJS-like module system
188    #[must_use]
189    pub const fn is_commonjs(self) -> bool {
190        matches!(
191            self,
192            Self::CommonJS | Self::UMD | Self::Node16 | Self::NodeNext
193        )
194    }
195
196    /// Check if this uses ES modules (import/export)
197    ///
198    /// Returns true only for pure ES module systems where `export =` is forbidden.
199    /// Node16/NodeNext are hybrid systems that support both `CommonJS` and `ESM`,
200    /// so they return false here (the checker must use file extension to decide).
201    #[must_use]
202    pub const fn is_es_module(self) -> bool {
203        matches!(
204            self,
205            Self::ES2015 | Self::ES2020 | Self::ES2022 | Self::ESNext | Self::Preserve
206        )
207    }
208}
209
210/// New line kind for source file emission.
211#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
212pub enum NewLineKind {
213    /// Line Feed (\n) - Unix, Linux, macOS
214    #[default]
215    LineFeed = 0,
216
217    /// Carriage Return + Line Feed (\r\n) - Windows
218    CarriageReturnLineFeed = 1,
219}
220
221impl NewLineKind {
222    /// Get the actual newline characters
223    #[must_use]
224    pub const fn as_bytes(&self) -> &'static [u8] {
225        match self {
226            Self::LineFeed => b"\n",
227            Self::CarriageReturnLineFeed => b"\r\n",
228        }
229    }
230
231    /// Get the newline as a string
232    #[must_use]
233    pub const fn as_str(&self) -> &'static str {
234        match self {
235            Self::LineFeed => "\n",
236            Self::CarriageReturnLineFeed => "\r\n",
237        }
238    }
239}
240
241#[cfg(test)]
242#[path = "../tests/common.rs"]
243mod tests;