Skip to content

Commit

Permalink
New syntax
Browse files Browse the repository at this point in the history
- still prefixed syntax
- uses {}  instead of ()
- puts those { behind the command, being more similar to function calls
- does not require wrapper chars for CSS selector anymore
  • Loading branch information
kelko committed Sep 5, 2022
1 parent a1a307f commit 31a551a
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 134 deletions.
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ Syntax
----------

The basic syntax is:
> (COMMAND SELECTOR) | (COMMAND SELECTOR)
> COMMAND{ SELECTOR } | COMMAND{ SELECTOR }
Some `COMMAND` use sub-pipelines, those would be written as follows:
> (COMMAND SELECTOR {(COMMAND SELECTOR) | (COMMAND SELECTOR)})
Some `COMMAND` use sub-pipelines. There are two kind of `COMMANDS` with this:
- "iterate"/"forEach": For each (sub) node matching the inner selector the sub-pipeline is processed, but the elements themselves are not changed

The `SELECTOR` is a [CSS selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors), wrapped in
either `"`, `'` or `?` (as to reduce the necessity of escaping to a minimum).
> COMMAND{ SELECTOR ↦ COMMAND{ SELECTOR } | COMMAND { SELECTOR } }
- "map"/"replace": For each (sub) node matching the inner selector the sub-pipeline is processed, and the pipelines result is used instead of the element

> COMMAND{ SELECTOR ↤ COMMAND{ SELECTOR } | COMMAND { SELECTOR } }
The `SELECTOR` is a [CSS selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors).

Commands
-------------
Expand Down Expand Up @@ -55,10 +60,10 @@ Example

```shell
# fetches all elements with CSS class "content" inside a <header> element
hse -i index.html '(ONLY ?header .content?)'
hse -i index.html 'ONLY{header .content}'
```

```shell
# fetches the `<main>` or element with CSS class `main`, but without any `<script>` defined inside
hse -i index.html '(ONLY ?main, .main?) | (WITHOUT ?script?)'
hse -i index.html 'ONLY{main, .main} | WITHOUT{script}'
```
16 changes: 6 additions & 10 deletions src/parsing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ parser! {
/ ":first-of-type" { CssPseudoClass::FirstOfType }
/ ":nth-child(" i:(number()) ")" { CssPseudoClass::NthChild(i) }
/ ":nth-of-type(" i:(number()) ")" { CssPseudoClass::NthOfType(i) }
/ ":last-child" { CssPseudoClass::LastChild }
/ ":last-of-type" { CssPseudoClass::LastOfType }
/ ":nth-last-child(" i:(number()) ")" { CssPseudoClass::NthLastChild(i) }
/ ":nth-last-of-type(" i:(number()) ")" { CssPseudoClass::NthLastOfType(i) }
rule css_pseudo_classes() -> Vec<CssPseudoClass>
= p:(css_pseudo_class() ++ "") { p }
rule css_id() -> &'input str
Expand All @@ -74,18 +78,10 @@ parser! {
= "\"" whitespace()? s:$([^'"']+) "\"" { s.trim() }
/ "'" whitespace()? s:$([^'\'']+) "'" { s.trim() }
/ "?" whitespace()? s:$([^'?']+) "?" { s.trim() }
pub(crate) rule enclosed_identifier() -> &'input str
= "\"" whitespace()? s:(identifier()) whitespace()? "\"" { s }
/ "'" whitespace()? s:(identifier()) whitespace()? "'" { s }
/ "?" whitespace()? s:(identifier()) whitespace()? "?" { s }
pub(crate) rule selector() -> CssSelectorList<'input>
= "\"" c:(css_selector_list()) "\"" { c }
/ "'" c:(css_selector_list()) "'" { c }
/ "?" c:(css_selector_list()) "?" { c }
pub(crate) rule only_command() -> Command<'input>
= "(" ("ONLY" / "SELECT") " " oc:selector() whitespace()? ")" { Command::Only(oc) }
= ("ONLY" / "SELECT") "{" whitespace()? oc:css_selector_list() whitespace()? "}" { Command::Only(oc) }
pub(crate) rule without_command() -> Command<'input>
= "(" ("WITHOUT" / "FILTER") " " oc:selector() whitespace()? ")" { Command::Without(oc) }
= ("WITHOUT" / "FILTER") "{" whitespace()? oc:css_selector_list() whitespace()? "}" { Command::Without(oc) }
rule command() -> Command<'input>
= only_command()
/ without_command()
Expand Down
119 changes: 5 additions & 114 deletions src/parsing/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,118 +60,9 @@ fn parse_value_questionmarked_cant_have_questionmarks() {
assert!(parsed.is_err())
}

#[test]
fn parse_identifier_simple_doublequotes() {
let parsed = super::grammar::enclosed_identifier("\"a\"");
assert_eq!(parsed, Ok("a"))
}

#[test]
fn parse_identifier_simple_singlequotes() {
let parsed = super::grammar::enclosed_identifier("'a'");
assert_eq!(parsed, Ok("a"))
}

#[test]
fn parse_identifier_simple_questionsmarks() {
let parsed = super::grammar::enclosed_identifier("?a?");
assert_eq!(parsed, Ok("a"))
}

#[test]
fn parse_identifier_whitespaced_questionsmarks() {
let parsed = super::grammar::enclosed_identifier("? a ?");
assert_eq!(parsed, Ok("a"))
}

#[test]
fn parse_identifier_whitespaced_doublequotes() {
let parsed = super::grammar::enclosed_identifier("\" a \"");
assert_eq!(parsed, Ok("a"))
}

#[test]
fn parse_identifier_whitespaced_singlequotes() {
let parsed = super::grammar::enclosed_identifier("' a '");
assert_eq!(parsed, Ok("a"))
}

#[test]
fn parse_identifier_underscore() {
let parsed = super::grammar::enclosed_identifier("\"a_b\"");
assert_eq!(parsed, Ok("a_b"))
}

#[test]
fn parse_identifier_dash() {
let parsed = super::grammar::enclosed_identifier("\"a-b\"");
assert_eq!(parsed, Ok("a-b"))
}

#[test]
fn parse_selector_simple_doublequotes() {
let parsed = super::grammar::selector("\"a\"");
assert_eq!(
parsed,
Ok(CssSelectorList::new(vec![CssSelectorPath::single(
CssSelector::for_element("a")
)]))
)
}

#[test]
fn parse_selector_simple_singlequotes() {
let parsed = super::grammar::selector("'a'");
assert_eq!(
parsed,
Ok(CssSelectorList::new(vec![CssSelectorPath::single(
CssSelector::for_element("a")
)]))
)
}

#[test]
fn parse_selector_whitespaced_doublequotes() {
let parsed = super::grammar::selector("\" a \"");
assert_eq!(
parsed,
Ok(CssSelectorList::new(vec![CssSelectorPath::single(
CssSelector::for_element("a")
)]))
)
}

#[test]
fn parse_selector_whitespaced_singlequotes() {
let parsed = super::grammar::selector("' a '");
assert_eq!(
parsed,
Ok(CssSelectorList::new(vec![CssSelectorPath::single(
CssSelector::for_element("a")
)]))
)
}

#[test]
fn parse_selector_whitespaced_questionsmarks() {
let parsed = super::grammar::selector("? a ?");
assert_eq!(
parsed,
Ok(CssSelectorList::new(vec![CssSelectorPath::single(
CssSelector::for_element("a")
)]))
)
}

#[test]
fn parse_selector_doublequoted_cant_have_doublequotes() {
let parsed = super::grammar::selector("\"a\"b\"");
assert!(parsed.is_err())
}

#[test]
fn parse_single_only() {
let parsed = super::grammar::only_command("(ONLY 'a')");
let parsed = super::grammar::only_command("ONLY{a}");
assert_eq!(
parsed,
Ok(Command::Only(CssSelectorList::new(vec![
Expand All @@ -182,7 +73,7 @@ fn parse_single_only() {

#[test]
fn parse_single_select_alias() {
let parsed = super::grammar::only_command("(SELECT 'a')");
let parsed = super::grammar::only_command("SELECT{a}");
assert_eq!(
parsed,
Ok(Command::Only(CssSelectorList::new(vec![
Expand All @@ -193,7 +84,7 @@ fn parse_single_select_alias() {

#[test]
fn parse_single_without() {
let parsed = super::grammar::without_command("(WITHOUT 'a')");
let parsed = super::grammar::without_command("WITHOUT{a}");
assert_eq!(
parsed,
Ok(Command::Without(CssSelectorList::new(vec![
Expand All @@ -204,7 +95,7 @@ fn parse_single_without() {

#[test]
fn parse_single_filter_alias() {
let parsed = super::grammar::without_command("(FILTER 'a')");
let parsed = super::grammar::without_command("FILTER{a}");
assert_eq!(
parsed,
Ok(Command::Without(CssSelectorList::new(vec![
Expand All @@ -215,7 +106,7 @@ fn parse_single_filter_alias() {

#[test]
fn parse_two_grammar() {
let parsed = super::grammar::pipeline("(ONLY 'a') | (WITHOUT 'b')");
let parsed = super::grammar::pipeline("ONLY{a} | WITHOUT{b}");
assert_eq!(
parsed,
Ok(Pipeline::new(vec![
Expand Down
4 changes: 2 additions & 2 deletions tests/only.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const HTML_INPUT: &str = r#"<html>

#[test]
fn only_first_para() -> Result<(), StreamingEditorError> {
let command = "(ONLY ?#first-para?)";
let command = "ONLY{#first-para}";

let mut input = Box::new(HTML_INPUT.as_bytes());
let mut output = Vec::new();
Expand All @@ -36,7 +36,7 @@ fn only_first_para() -> Result<(), StreamingEditorError> {

#[test]
fn only_list_items() -> Result<(), StreamingEditorError> {
let command = "(ONLY ?li?)";
let command = "ONLY{li}";

let mut input = Box::new(HTML_INPUT.as_bytes());
let mut output = Vec::new();
Expand Down
2 changes: 1 addition & 1 deletion tests/without.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const HTML_INPUT: &str = r#"<html><head></head><body><h1>Title</h1><p id="first-

#[test]
fn without_first_para() -> Result<(), StreamingEditorError> {
let command = "(WITHOUT ?#first-para?)";
let command = "WITHOUT{#first-para}";

let mut input = Box::new(HTML_INPUT.as_bytes());
let mut output = Vec::new();
Expand Down

0 comments on commit 31a551a

Please sign in to comment.