pub mod markup;
pub mod regexes;
pub mod script;
pub mod style;
use markup::*;
use minify_selectors_utils::*;
use onig::*;
use script::*;
use style::*;
pub fn read_from_css(
file_string: &mut str,
selectors: &mut Selectors,
config: &Config,
) {
analyse_css(file_string, selectors, config);
}
pub fn write_to_css(
file_string: &mut String,
selectors: &Selectors,
config: &Config,
) {
rewrite_css(file_string, selectors, config);
}
pub fn read_from_html(
file_string: &mut str,
selectors: &mut Selectors,
config: &Config,
) {
analyse_html(file_string, selectors, config, None);
}
pub fn write_to_html(
file_string: &mut String,
selectors: &Selectors,
config: &Config,
) {
rewrite_html(file_string, selectors, config);
}
pub fn read_from_js(
file_string: &mut str,
selectors: &mut Selectors,
config: &Config,
) {
analyse_js(file_string, selectors, config);
}
pub fn write_to_js(
file_string: &mut String,
selectors: &Selectors,
config: &Config,
) {
rewrite_js(file_string, selectors, config);
}
pub fn add_selector_to_map(
selector: &str,
selectors: &mut Selectors,
usage: Option<SelectorUsage>,
) {
selectors.add(selector.to_owned(), usage);
}
pub fn get_encoded_selector(
selector: &str,
selectors: &Selectors,
) -> Option<String> {
if let Some(encoded_selector) = selectors.map.get(selector) {
if encoded_selector.replacement.is_some() {
encoded_selector.replacement.clone()
} else {
None
}
} else {
Some(selector.to_owned())
}
}
pub fn get_function_arguments(string: &str) -> FindCaptures {
regexes::STRING_DELIMITED_BY_COMMA.captures_iter(string)
}
pub fn is_prefixed_selector(string: &str) -> bool {
regexes::PREFIXED_SELECTORS.find(string).is_some()
}
pub fn analyse_prefixed_selectors(
file_string: &mut str,
selectors: &mut Selectors,
) {
for capture in regexes::PREFIXED_SELECTORS.captures_iter(file_string) {
if capture.at(2) == Some("ignore") {
continue;
}
let mut indentifier = unescape_css_chars(capture.at(3).unwrap().trim());
match capture.at(2) {
Some("class") => indentifier = format!(".{indentifier}"),
Some("id") => indentifier = format!("#{indentifier}"),
Some(&_) | None => {
indentifier = format!(
"{prefix}{name}",
prefix = capture.at(1).unwrap(),
name = indentifier,
)
},
}
add_selector_to_map(&indentifier, selectors, Some(SelectorUsage::Prefix));
}
}
pub fn rewrite_prefixed_selectors(
file_string: &mut String,
selectors: &Selectors,
) {
*file_string = regexes::PREFIXED_SELECTORS.replace_all(file_string, |capture: &Captures| {
let mut indentifier = unescape_css_chars(capture.at(3).unwrap().trim());
match capture.at(2) {
Some("class") => {
indentifier = get_encoded_selector(&format!(".{indentifier}"), selectors)
.unwrap_or(indentifier);
},
Some("id") => {
indentifier = get_encoded_selector(&format!("#{indentifier}"), selectors)
.unwrap_or(indentifier);
},
Some("ignore") => {
indentifier = format!(
"{prefix}{name}",
prefix = capture.at(1).unwrap_or(""),
name = indentifier,
);
},
Some(&_) | None => {
indentifier = format!(
"{prefix}{name}",
prefix = capture.at(1).unwrap(),
name = get_encoded_selector(
&format!(
"{prefix}{name}",
prefix = capture.at(1).unwrap(),
name = indentifier,
),
selectors,
)
.unwrap_or(indentifier)
);
},
}
indentifier
});
}
pub fn analyse_string_of_tokens(
string: &mut String,
selectors: &mut Selectors,
context: &str,
usage: Option<SelectorUsage>,
) {
let prefix: &str = match context {
"class" => ".",
"id" => "#",
_ => "",
};
let quote_type: &str = match string.chars().next() {
Some('\'') if string.len() >= 2 => "'",
Some('"') if string.len() >= 2 => "\"",
Some('`') if string.len() >= 2 => "`",
_ => "",
};
if !quote_type.is_empty() {
string.pop();
string.remove(0);
}
for capture in regexes::STRING_DELIMITED_BY_SPACE.captures_iter(string) {
if !is_prefixed_selector(capture.at(0).unwrap()) {
add_selector_to_map(
&format!(
"{prefix}{token}",
prefix = prefix,
token = unescape_css_chars(capture.at(1).unwrap()),
),
selectors,
usage,
);
}
}
}
pub fn rewrite_string_of_tokens(
string: &mut String,
selectors: &Selectors,
context: &str,
) {
let prefix: &str = match context {
"class" => ".",
"id" => "#",
_ => "",
};
let quote_type: &str = match string.chars().next() {
Some('\'') if string.len() >= 2 => "'",
Some('"') if string.len() >= 2 => "\"",
Some('`') if string.len() >= 2 => "`",
_ => "",
};
if !quote_type.is_empty() {
string.pop();
string.remove(0);
}
*string = format!(
"{quote}{tokens}{quote}",
tokens = regexes::STRING_DELIMITED_BY_SPACE.replace_all(string, |capture: &Captures| {
if is_prefixed_selector(capture.at(0).unwrap()) {
return capture.at(0).unwrap().to_string();
}
get_encoded_selector(
&format!(
"{prefix}{token}",
prefix = prefix,
token = unescape_css_chars(capture.at(1).unwrap())
),
selectors,
)
.unwrap_or_else(|| capture.at(1).unwrap().to_string())
}),
quote = quote_type,
);
}
pub fn analyse_string_of_arguments(
string: &mut str,
selectors: &mut Selectors,
context: &str,
usage: Option<SelectorUsage>,
) {
let prefix: &str = match context {
"class" => ".",
"id" => "#",
_ => "",
};
for capture in regexes::STRING_DELIMITED_BY_COMMA.captures_iter(string) {
if is_prefixed_selector(capture.at(0).unwrap()) {
continue;
}
if capture.at(3).is_some() {
add_selector_to_map(
&format!(
"{prefix}{token}",
prefix = prefix,
token = capture.at(3).unwrap(),
),
selectors,
usage,
);
}
}
}
pub fn rewrite_string_of_arguments(
string: &mut String,
selectors: &Selectors,
context: &str,
) {
let prefix: &str = match context {
"class" => ".",
"id" => "#",
_ => "",
};
*string = regexes::STRING_DELIMITED_BY_COMMA.replace_all(string, |capture: &Captures| {
if is_prefixed_selector(capture.at(0).unwrap()) {
return capture.at(0).unwrap().to_string();
}
if capture.at(3).is_some() {
format!(
"{quote}{argument}{quote}",
argument = get_encoded_selector(
&format!(
"{prefix}{token}",
prefix = prefix,
token = capture.at(3).unwrap(),
),
selectors,
)
.unwrap_or_else(|| capture.at(3).unwrap().to_string()),
quote = capture.at(2).unwrap(),
)
} else {
return capture.at(0).unwrap().to_string();
}
});
}
pub fn analyse_anchor_links(
string: &mut String,
selectors: &mut Selectors,
) {
let quote_type: &str = match string.chars().next() {
Some('\'') => "'",
Some('"') => "\"",
Some('`') => "`",
_ => "",
};
if !quote_type.is_empty() {
string.pop();
string.remove(0);
}
for capture in regexes::INTERNAL_ANCHOR_TARGET_ID.captures_iter(string) {
if capture.at(1).is_none() {
continue;
}
add_selector_to_map(
&unescape_js_chars(capture.at(2).unwrap()),
selectors,
Some(SelectorUsage::Anchor),
);
}
}
pub fn rewrite_anchor_links(
string: &mut String,
selectors: &Selectors,
) {
let quote_type: &str = match string.chars().next() {
Some('\'') => "'",
Some('"') => "\"",
Some('`') => "`",
_ => "",
};
if !quote_type.is_empty() {
string.pop();
string.remove(0);
}
*string = format!(
"{quote}{url}{quote}",
url = regexes::INTERNAL_ANCHOR_TARGET_ID.replace(string, |capture: &Captures| {
if capture.at(1).is_none() {
return capture.at(0).unwrap().to_string();
}
format!(
"{url}#{target_id}",
url = capture.at(1).unwrap_or(""),
target_id =
get_encoded_selector(&unescape_js_chars(capture.at(2).unwrap()), selectors,)
.unwrap_or_else(|| capture.at(2).unwrap().to_string()),
)
}),
quote = quote_type,
);
}