swc_ecma_lexer/common/
syntax.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
4#[serde(deny_unknown_fields, tag = "syntax")]
5pub enum Syntax {
6    /// Standard
7    #[serde(rename = "ecmascript")]
8    Es(EsSyntax),
9    /// This variant requires the cargo feature `typescript` to be enabled.
10    #[cfg(feature = "typescript")]
11    #[cfg_attr(docsrs, doc(cfg(feature = "typescript")))]
12    #[serde(rename = "typescript")]
13    Typescript(TsSyntax),
14}
15
16impl Default for Syntax {
17    fn default() -> Self {
18        Syntax::Es(Default::default())
19    }
20}
21
22impl Syntax {
23    pub fn auto_accessors(self) -> bool {
24        match self {
25            Syntax::Es(EsSyntax {
26                auto_accessors: true,
27                ..
28            }) => true,
29            #[cfg(feature = "typescript")]
30            Syntax::Typescript(_) => true,
31            _ => false,
32        }
33    }
34
35    pub fn import_attributes(self) -> bool {
36        true
37    }
38
39    /// Should we parse jsx?
40    pub fn jsx(self) -> bool {
41        match self {
42            Syntax::Es(EsSyntax { jsx: true, .. }) => true,
43            #[cfg(feature = "typescript")]
44            Syntax::Typescript(TsSyntax { tsx: true, .. }) => true,
45            _ => false,
46        }
47    }
48
49    pub fn fn_bind(self) -> bool {
50        matches!(self, Syntax::Es(EsSyntax { fn_bind: true, .. }))
51    }
52
53    pub fn decorators(self) -> bool {
54        match self {
55            Syntax::Es(EsSyntax {
56                decorators: true, ..
57            }) => true,
58            #[cfg(feature = "typescript")]
59            Syntax::Typescript(TsSyntax {
60                decorators: true, ..
61            }) => true,
62            _ => false,
63        }
64    }
65
66    pub fn decorators_before_export(self) -> bool {
67        match self {
68            Syntax::Es(EsSyntax {
69                decorators_before_export: true,
70                ..
71            }) => true,
72            #[cfg(feature = "typescript")]
73            Syntax::Typescript(..) => true,
74            _ => false,
75        }
76    }
77
78    /// Should we parse typescript?
79    #[cfg(not(feature = "typescript"))]
80    pub const fn typescript(self) -> bool {
81        false
82    }
83
84    /// Should we parse typescript?
85    #[cfg(feature = "typescript")]
86    pub const fn typescript(self) -> bool {
87        matches!(self, Syntax::Typescript(..))
88    }
89
90    pub fn export_default_from(self) -> bool {
91        matches!(
92            self,
93            Syntax::Es(EsSyntax {
94                export_default_from: true,
95                ..
96            })
97        )
98    }
99
100    pub fn dts(self) -> bool {
101        match self {
102            #[cfg(feature = "typescript")]
103            Syntax::Typescript(t) => t.dts,
104            _ => false,
105        }
106    }
107
108    pub fn allow_super_outside_method(self) -> bool {
109        match self {
110            Syntax::Es(EsSyntax {
111                allow_super_outside_method,
112                ..
113            }) => allow_super_outside_method,
114            #[cfg(feature = "typescript")]
115            Syntax::Typescript(_) => true,
116        }
117    }
118
119    pub fn allow_return_outside_function(self) -> bool {
120        match self {
121            Syntax::Es(EsSyntax {
122                allow_return_outside_function,
123                ..
124            }) => allow_return_outside_function,
125            #[cfg(feature = "typescript")]
126            Syntax::Typescript(_) => false,
127        }
128    }
129
130    pub fn early_errors(self) -> bool {
131        match self {
132            #[cfg(feature = "typescript")]
133            Syntax::Typescript(t) => !t.no_early_errors,
134            Syntax::Es(..) => true,
135        }
136    }
137
138    pub fn disallow_ambiguous_jsx_like(self) -> bool {
139        match self {
140            #[cfg(feature = "typescript")]
141            Syntax::Typescript(t) => t.disallow_ambiguous_jsx_like,
142            _ => false,
143        }
144    }
145
146    pub fn explicit_resource_management(&self) -> bool {
147        match self {
148            Syntax::Es(EsSyntax {
149                explicit_resource_management: using_decl,
150                ..
151            }) => *using_decl,
152            #[cfg(feature = "typescript")]
153            Syntax::Typescript(_) => true,
154        }
155    }
156
157    pub fn into_flags(self) -> SyntaxFlags {
158        match self {
159            Syntax::Es(es) => es.into_flags(),
160            #[cfg(feature = "typescript")]
161            Syntax::Typescript(ts) => ts.into_flags(),
162        }
163    }
164}
165
166#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
167#[serde(rename_all = "camelCase")]
168pub struct TsSyntax {
169    #[serde(default)]
170    pub tsx: bool,
171
172    #[serde(default)]
173    pub decorators: bool,
174
175    /// `.d.ts`
176    #[serde(skip, default)]
177    pub dts: bool,
178
179    #[serde(skip, default)]
180    pub no_early_errors: bool,
181
182    /// babel: `disallowAmbiguousJSXLike`
183    /// Even when JSX parsing is not enabled, this option disallows using syntax
184    /// that would be ambiguous with JSX (`<X> y` type assertions and
185    /// `<X>()=>{}` type arguments)
186    /// see: https://babeljs.io/docs/en/babel-plugin-transform-typescript#disallowambiguousjsxlike
187    #[serde(skip, default)]
188    pub disallow_ambiguous_jsx_like: bool,
189}
190
191impl TsSyntax {
192    fn into_flags(self) -> SyntaxFlags {
193        let mut flags = SyntaxFlags::TS
194            .union(SyntaxFlags::AUTO_ACCESSORS)
195            .union(SyntaxFlags::IMPORT_ATTRIBUTES)
196            .union(SyntaxFlags::DECORATORS_BEFORE_EXPORT)
197            .union(SyntaxFlags::ALLOW_SUPER_OUTSIDE_METHOD)
198            .union(SyntaxFlags::EXPLICIT_RESOURCE_MANAGEMENT);
199
200        if self.tsx {
201            flags |= SyntaxFlags::JSX;
202        }
203        if self.decorators {
204            flags |= SyntaxFlags::DECORATORS;
205        }
206        if self.dts {
207            flags |= SyntaxFlags::DTS;
208        }
209        if self.no_early_errors {
210            flags |= SyntaxFlags::NO_EARLY_ERRORS;
211        }
212        if self.disallow_ambiguous_jsx_like {
213            flags |= SyntaxFlags::DISALLOW_AMBIGUOUS_JSX_LIKE;
214        }
215        flags
216    }
217}
218
219#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
220#[serde(rename_all = "camelCase")]
221pub struct EsSyntax {
222    #[serde(default)]
223    pub jsx: bool,
224
225    /// Support function bind expression.
226    #[serde(rename = "functionBind")]
227    #[serde(default)]
228    pub fn_bind: bool,
229
230    /// Enable decorators.
231    #[serde(default)]
232    pub decorators: bool,
233
234    /// babel: `decorators.decoratorsBeforeExport`
235    ///
236    /// Effective only if `decorator` is true.
237    #[serde(rename = "decoratorsBeforeExport")]
238    #[serde(default)]
239    pub decorators_before_export: bool,
240
241    #[serde(default)]
242    pub export_default_from: bool,
243
244    /// Stage 4
245    /// Always true in swc
246    #[serde(default, alias = "importAssertions")]
247    pub import_attributes: bool,
248
249    #[serde(default, rename = "allowSuperOutsideMethod")]
250    pub allow_super_outside_method: bool,
251
252    #[serde(default, rename = "allowReturnOutsideFunction")]
253    pub allow_return_outside_function: bool,
254
255    #[serde(default)]
256    pub auto_accessors: bool,
257
258    #[serde(default)]
259    pub explicit_resource_management: bool,
260}
261
262impl EsSyntax {
263    fn into_flags(self) -> SyntaxFlags {
264        let mut flags = SyntaxFlags::empty();
265        if self.jsx {
266            flags |= SyntaxFlags::JSX;
267        }
268        if self.fn_bind {
269            flags |= SyntaxFlags::FN_BIND;
270        }
271        if self.decorators {
272            flags |= SyntaxFlags::DECORATORS;
273        }
274        if self.decorators_before_export {
275            flags |= SyntaxFlags::DECORATORS_BEFORE_EXPORT;
276        }
277        if self.export_default_from {
278            flags |= SyntaxFlags::EXPORT_DEFAULT_FROM;
279        }
280        if self.import_attributes {
281            flags |= SyntaxFlags::IMPORT_ATTRIBUTES;
282        }
283        if self.allow_super_outside_method {
284            flags |= SyntaxFlags::ALLOW_SUPER_OUTSIDE_METHOD;
285        }
286        if self.allow_return_outside_function {
287            flags |= SyntaxFlags::ALLOW_RETURN_OUTSIDE_FUNCTION;
288        }
289        if self.auto_accessors {
290            flags |= SyntaxFlags::AUTO_ACCESSORS;
291        }
292        if self.explicit_resource_management {
293            flags |= SyntaxFlags::EXPLICIT_RESOURCE_MANAGEMENT;
294        }
295        flags
296    }
297}
298
299impl SyntaxFlags {
300    #[inline(always)]
301    pub const fn auto_accessors(&self) -> bool {
302        self.contains(Self::AUTO_ACCESSORS)
303    }
304
305    #[inline(always)]
306    pub const fn import_attributes(&self) -> bool {
307        true
308    }
309
310    /// Should we parse jsx?
311    #[inline(always)]
312    pub const fn jsx(&self) -> bool {
313        self.contains(SyntaxFlags::JSX)
314    }
315
316    #[inline(always)]
317    pub const fn fn_bind(&self) -> bool {
318        self.contains(SyntaxFlags::FN_BIND)
319    }
320
321    #[inline(always)]
322    pub const fn decorators(&self) -> bool {
323        self.contains(SyntaxFlags::DECORATORS)
324    }
325
326    #[inline(always)]
327    pub const fn decorators_before_export(&self) -> bool {
328        self.contains(SyntaxFlags::DECORATORS_BEFORE_EXPORT)
329    }
330
331    /// Should we parse typescript?
332    #[cfg(not(feature = "typescript"))]
333    #[inline(always)]
334    pub const fn typescript(&self) -> bool {
335        false
336    }
337
338    /// Should we parse typescript?
339    #[cfg(feature = "typescript")]
340    #[inline(always)]
341    pub const fn typescript(&self) -> bool {
342        self.contains(SyntaxFlags::TS)
343    }
344
345    #[inline(always)]
346    pub const fn export_default_from(&self) -> bool {
347        self.contains(SyntaxFlags::EXPORT_DEFAULT_FROM)
348    }
349
350    #[inline(always)]
351    pub const fn dts(&self) -> bool {
352        self.contains(SyntaxFlags::DTS)
353    }
354
355    #[inline(always)]
356    pub const fn allow_super_outside_method(&self) -> bool {
357        self.contains(SyntaxFlags::ALLOW_SUPER_OUTSIDE_METHOD)
358    }
359
360    #[inline(always)]
361    pub const fn allow_return_outside_function(&self) -> bool {
362        self.contains(SyntaxFlags::ALLOW_RETURN_OUTSIDE_FUNCTION)
363    }
364
365    #[inline(always)]
366    pub const fn early_errors(&self) -> bool {
367        !self.contains(SyntaxFlags::NO_EARLY_ERRORS)
368    }
369
370    #[inline(always)]
371    pub const fn disallow_ambiguous_jsx_like(&self) -> bool {
372        self.contains(SyntaxFlags::TS.union(SyntaxFlags::DISALLOW_AMBIGUOUS_JSX_LIKE))
373    }
374
375    #[inline(always)]
376    pub const fn explicit_resource_management(&self) -> bool {
377        self.contains(SyntaxFlags::EXPLICIT_RESOURCE_MANAGEMENT)
378    }
379}
380
381bitflags::bitflags! {
382    #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
383    pub struct SyntaxFlags: u16 {
384        const JSX = 1 << 0;
385        const FN_BIND = 1 << 1;
386        const DECORATORS = 1 << 2;
387        const DECORATORS_BEFORE_EXPORT = 1 << 3;
388        const EXPORT_DEFAULT_FROM = 1 << 4;
389        const IMPORT_ATTRIBUTES = 1 << 5;
390        const ALLOW_SUPER_OUTSIDE_METHOD = 1 << 6;
391        const ALLOW_RETURN_OUTSIDE_FUNCTION = 1 << 7;
392        const AUTO_ACCESSORS = 1 << 8;
393        const EXPLICIT_RESOURCE_MANAGEMENT = 1 << 9;
394        const DTS = 1 << 10;
395        const NO_EARLY_ERRORS = 1 << 11;
396        const DISALLOW_AMBIGUOUS_JSX_LIKE = 1 << 12;
397        const TS = 1 << 13;
398    }
399}