swc_ecma_lints/rules/
utils.rs

1use serde::{Deserialize, Serialize};
2use swc_atoms::Atom;
3use swc_common::SyntaxContext;
4use swc_ecma_ast::{Expr, Lit, MemberExpr, MemberProp, Number, Regex, Str, TaggedTpl, Tpl};
5
6#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
7#[serde(rename_all = "lowercase")]
8pub enum QuotesType {
9    Single,
10    Double,
11    Backtick,
12}
13
14impl Default for QuotesType {
15    fn default() -> Self {
16        Self::Double
17    }
18}
19
20impl QuotesType {
21    pub fn get_char(&self) -> char {
22        match self {
23            QuotesType::Backtick => '`',
24            QuotesType::Double => '"',
25            QuotesType::Single => '\'',
26        }
27    }
28}
29
30pub fn resolve_string_quote_type(lit_str: &Str) -> Option<QuotesType> {
31    lit_str.raw.as_ref().and_then(|raw| {
32        let byte = raw.as_bytes()[0];
33
34        match byte {
35            b'\'' => Some(QuotesType::Single),
36            b'"' => Some(QuotesType::Double),
37            b'`' => Some(QuotesType::Backtick),
38            _ => None,
39        }
40    })
41}
42
43#[derive(Debug)]
44pub enum ArgValue {
45    Str(Atom),
46    Number(f64),
47    RegExp { exp: Atom, flags: Atom },
48    Ident,
49    Other,
50}
51
52pub fn extract_arg_val(unresolved_ctxt: SyntaxContext, expr: &Expr) -> ArgValue {
53    match expr {
54        Expr::Ident(_) => ArgValue::Ident,
55        Expr::Lit(Lit::Str(Str { value, .. })) => ArgValue::Str(Atom::new(value.to_string_lossy())),
56        Expr::Lit(Lit::Num(Number { value, .. })) => ArgValue::Number(*value),
57        Expr::Lit(Lit::Regex(Regex { exp, flags, .. })) => ArgValue::RegExp {
58            exp: exp.clone(),
59            flags: flags.clone(),
60        },
61        Expr::Tpl(Tpl { exprs, quasis, .. }) => {
62            if exprs.is_empty() {
63                ArgValue::Str(quasis.first().unwrap().raw.clone())
64            } else {
65                ArgValue::Other
66            }
67        }
68        Expr::TaggedTpl(TaggedTpl { tag, tpl, .. }) => {
69            if tpl.exprs.is_empty() {
70                if let Expr::Member(MemberExpr { obj, prop, .. }) = tag.as_ref() {
71                    if let (Expr::Ident(obj), MemberProp::Ident(prop)) = (obj.as_ref(), prop) {
72                        if &*obj.sym != "String" {
73                            return ArgValue::Other;
74                        }
75
76                        if obj.ctxt != unresolved_ctxt {
77                            return ArgValue::Other;
78                        }
79
80                        if &prop.sym != "raw" {
81                            return ArgValue::Other;
82                        }
83
84                        return ArgValue::Str(tpl.quasis.first().unwrap().raw.clone());
85                    }
86                }
87            }
88
89            ArgValue::Other
90        }
91        _ => ArgValue::Other,
92    }
93}