Skip to main content

swc_experimental_ecma_parser/
syntax.rs

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