Skip to main content

stylex_regex/
regex.rs

1use fancy_regex::Regex;
2use once_cell::sync::Lazy;
3
4// Extracts CSS property value from a rule (e.g., "color: red;" -> "red")
5pub static CSS_RULE_REGEX: Lazy<Regex> =
6  Lazy::new(|| Regex::new(r"\w+:\s*([^;}]+);?").expect("CSS rule regex is valid"));
7
8// Normalizes whitespace around math operators in CSS calc() and similar functions
9// Uses named groups for better readability and maintenance
10pub static WHITESPACE_NORMALIZER_MATH_SIGNS_REGEX: Lazy<Regex> = Lazy::new(|| {
11  Regex::new(
12    r"(?x)
13    (?<left>\d+%?|\))       # Left operand: number with optional %, or closing paren
14    (?<lspace>\s*)          # Optional whitespace before operator
15    (?<op>[+\-*/%])         # Operator
16    (?<rspace>\s*)          # Optional whitespace after operator
17    (?<right>\d*\.?\d+|\()  # Right operand: number (with optional decimal), or opening paren
18  ",
19  )
20  .expect("Whitespace normalizer math signs regex is valid")
21});
22
23pub static SANITIZE_CLASS_NAME_REGEX: Lazy<Regex> =
24  Lazy::new(|| Regex::new(r"[^.a-zA-Z0-9_-]").expect("Sanitize class name regex is valid"));
25
26// Normalizes spacing around brackets and quotes: ")a" -> ") a", """" -> ""
27pub static WHITESPACE_BRACKET_NORMALIZER_REGEX: Lazy<Regex> = Lazy::new(|| {
28  Regex::new(r#"(\))(\S)|(\")(\")"#).expect("Whitespace bracket normalizer regex is valid")
29});
30
31// Normalizes function arguments: "( arg )" -> "(arg)"
32// Uses possessive quantifiers for better performance
33pub static WHITESPACE_FUNC_NORMALIZER_REGEX: Lazy<Regex> = Lazy::new(|| {
34  Regex::new(r#"\(\s*+([^)]*?)\s*+\)\s*+,\s*+"#)
35    .expect("Whitespace function normalizer regex is valid")
36});
37
38// Adds space before hash in color values: "a#fff" -> "a #fff"
39pub static HASH_WHITESPACE_NORMALIZER_REGEX: Lazy<Regex> =
40  Lazy::new(|| Regex::new(r"(\S)#").expect("Hash whitespace normalizer regex is valid"));
41
42// Updated to include modern CSS units: dvh, dvw, lvh, lvw, svh, svw, cqw, cqh, cqi, cqb, cqmin, cqmax
43pub static LENGTH_UNIT_TESTER_REGEX: Lazy<Regex> = Lazy::new(|| {
44  Regex::new(r"^-?\d+(?:px|%|em|rem|ex|ch|vh|vw|vmin|vmax|dvh|dvw|lvh|lvw|svh|svw|cqw|cqh|cqi|cqb|cqmin|cqmax)?$")
45    .expect("Length unit tester regex is valid")
46});
47
48// Improved: Non-greedy matching to avoid over-matching
49pub static CSS_URL_REGEX: Lazy<Regex> =
50  Lazy::new(|| Regex::new(r#"url\([^)]+\)"#).expect("CSS URL regex is valid"));
51
52// Note: This is identical to WHITESPACE_BRACKET_NORMALIZER_REGEX - using the same pattern
53pub static CSS_PROPERTY_KEY: Lazy<Regex> =
54  Lazy::new(|| Regex::new(r#"(\))(\S)|(\")(\")"#).expect("CSS property key regex is valid"));
55
56pub static CLEAN_CSS_VAR: Lazy<Regex> =
57  Lazy::new(|| Regex::new(r#"\\3(\d) "#).expect("Clean CSS var regex is valid"));
58
59// Updated: More permissive CSS variable name matching (allows dots, underscores, etc.)
60pub static IS_CSS_VAR: Lazy<Regex> =
61  Lazy::new(|| Regex::new(r#"^var\(--[\w-]+\)$"#).expect("Is CSS var regex is valid"));
62
63pub static MANY_SPACES: Lazy<Regex> =
64  Lazy::new(|| Regex::new(r#"\s+"#).expect("Many spaces regex is valid"));
65
66pub static WHITESPACE_NORMALIZER_EXTRA_SPACES_REGEX: Lazy<Regex> = Lazy::new(|| {
67  Regex::new(
68    r#"(?x)
69      # Empty string quotes
70      ^(\")\s(\")$ |
71      # Multiple closing parens
72      (\))\s+(\))
73  "#,
74  )
75  .expect("Whitespace normalizer extra spaces regex is valid")
76});
77
78// Improved: Using positive lookbehind to avoid capturing the prefix
79// This simplifies replacement from "$1-$2" to "-$1"
80pub static DASHIFY_REGEX: Lazy<Regex> =
81  Lazy::new(|| Regex::new(r"(?<=^|[a-z])([A-Z])").expect("Dashify regex is valid"));
82
83pub static URL_REGEX: Lazy<Regex> = Lazy::new(|| {
84  Regex::new(
85        r"https?://(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&//=]*)"
86    ).expect("URL regex is valid")
87});
88
89pub static JSON_REGEX: Lazy<Regex> =
90  Lazy::new(|| Regex::new(r#"(\{|,)\s*([a-zA-Z0-9_$*-]+)\s*:"#).expect("JSON regex is valid"));
91
92pub static NPM_NAME_REGEX: Lazy<Regex> = Lazy::new(|| {
93  Regex::new(r"^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$")
94    .expect("NPM name regex is valid")
95});
96
97// #region Relational selectors for .when() functions
98pub static ANCESTOR_SELECTOR: Lazy<Regex> = Lazy::new(|| {
99  Regex::new(r"^:where\(\.[0-9a-zA-Z_-]+(:[a-zA-Z-]+)\s+\*\)$")
100    .expect("Ancestor selector regex is valid")
101});
102
103pub static DESCENDANT_SELECTOR: Lazy<Regex> = Lazy::new(|| {
104  Regex::new(r"^:where\(:has\(\.[0-9a-zA-Z_-]+(:[a-zA-Z-]+)\)\)$")
105    .expect("Descendant selector regex is valid")
106});
107
108pub static SIBLING_BEFORE_SELECTOR: Lazy<Regex> = Lazy::new(|| {
109  Regex::new(r"^:where\(\.[0-9a-zA-Z_-]+(:[a-zA-Z-]+)\s+~\s+\*\)$")
110    .expect("Sibling before selector regex is valid")
111});
112
113pub static SIBLING_AFTER_SELECTOR: Lazy<Regex> = Lazy::new(|| {
114  Regex::new(r"^:where\(:has\(~\s\.[0-9a-zA-Z_-]+(:[a-zA-Z-]+)\)\)$")
115    .expect("Sibling after selector regex is valid")
116});
117
118pub static ANY_SIBLING_SELECTOR: Lazy<Regex> = Lazy::new(|| {
119  Regex::new(r"^:where\(\.[0-9a-zA-Z_-]+(:[a-zA-Z-]+)\s+~\s+\*,\s+:has\(~\s\.[0-9a-zA-Z_-]+(:[a-zA-Z-]+)\)\)$")
120    .expect("Any sibling selector regex is valid")
121});
122// #endregion Relational selectors for .when() functions
123
124// Matches pseudo-elements (::after) and pseudo-classes (:hover, :nth-child(2))
125pub static PSEUDO_PART_REGEX: Lazy<Regex> = Lazy::new(|| {
126  Regex::new(r"::[a-zA-Z-]+|:[a-zA-Z-]+(?:\([^)]*\))?").expect("Pseudo part regex is valid")
127});
128
129// Matches .stylex or .consts file imports with optional extensions (.ts, .js, .tsx, .jsx)
130pub static STYLEX_CONSTS_IMPORT_REGEX: Lazy<Regex> = Lazy::new(|| {
131  Regex::new(r"\.(stylex|consts)(?:\.(.+){2,6})?$").expect("StyleX consts import regex is valid")
132});
133
134pub static VAR_EXTRACTION_REGEX: Lazy<Regex> =
135  Lazy::new(|| Regex::new(r"var\((--x-[^,)]+)[^)]*\)").expect("Var extraction regex is valid"));