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;