oxc_regular_expression/ast_impl/
support.rs1use crate::ast::{
2 Alternative, CharacterClass, CharacterClassContents, Disjunction, LookAroundAssertionKind,
3 Pattern, Term,
4};
5
6pub struct RegexUnsupportedPatterns {
7 pub named_capture_groups: bool,
8 pub unicode_property_escapes: bool,
9 pub look_behind_assertions: bool,
10 pub pattern_modifiers: bool,
11}
12
13pub fn has_unsupported_regular_expression_pattern(
17 pattern: &Pattern,
18 unsupported: &RegexUnsupportedPatterns,
19) -> bool {
20 disjunction_contains_unsupported(&pattern.body, unsupported)
21}
22
23fn disjunction_contains_unsupported(
24 disjunction: &Disjunction,
25 unsupported: &RegexUnsupportedPatterns,
26) -> bool {
27 disjunction
28 .body
29 .iter()
30 .any(|alternative| alternative_contains_unsupported(alternative, unsupported))
31}
32
33fn alternative_contains_unsupported(
34 alternative: &Alternative,
35 unsupported: &RegexUnsupportedPatterns,
36) -> bool {
37 alternative.body.iter().any(|term| term_contains_unsupported(term, unsupported))
38}
39
40fn term_contains_unsupported(term: &Term, unsupported: &RegexUnsupportedPatterns) -> bool {
41 match term {
42 Term::LookAroundAssertion(assertion) => {
43 if unsupported.look_behind_assertions
44 && matches!(
45 assertion.kind,
46 LookAroundAssertionKind::Lookbehind
47 | LookAroundAssertionKind::NegativeLookbehind
48 )
49 {
50 return true;
51 }
52 disjunction_contains_unsupported(&assertion.body, unsupported)
53 }
54 Term::Quantifier(quantifier) => term_contains_unsupported(&quantifier.body, unsupported),
55 Term::UnicodePropertyEscape(_) => unsupported.unicode_property_escapes,
56 Term::CharacterClass(character_class) => {
57 unsupported.unicode_property_escapes
58 && character_class_has_unicode_property_escape(character_class)
59 }
60 Term::CapturingGroup(group) => {
61 if group.name.is_some() && unsupported.named_capture_groups {
62 return true;
63 }
64 disjunction_contains_unsupported(&group.body, unsupported)
65 }
66 Term::IgnoreGroup(group) => {
67 if group.modifiers.is_some() && unsupported.pattern_modifiers {
68 return true;
69 }
70 disjunction_contains_unsupported(&group.body, unsupported)
71 }
72 _ => false,
73 }
74}
75
76fn character_class_has_unicode_property_escape(character_class: &CharacterClass) -> bool {
77 character_class.body.iter().any(|element| match element {
78 CharacterClassContents::UnicodePropertyEscape(_) => true,
79 CharacterClassContents::NestedCharacterClass(character_class) => {
80 character_class_has_unicode_property_escape(character_class)
81 }
82 _ => false,
83 })
84}