Skip to content

Commit

Permalink
Working and tested
Browse files Browse the repository at this point in the history
  • Loading branch information
sirreal committed Nov 28, 2024
1 parent 8d92994 commit 370539b
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 37 deletions.
83 changes: 48 additions & 35 deletions src/wp-includes/html-api/class-wp-css-selectors.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,21 +117,31 @@ private static function parse( string $input ) {
$input = str_replace( array( "\r", "\f" ), "\n", $input );
$input = str_replace( "\0", "\u{FFFD}", $input );

$length = strlen( $input );
$selectors = array();

$offset = 0;

while ( $offset < $length ) {
$selector = WP_CSS_ID_Selector::parse( $input, $offset );
if ( null !== $selector ) {
$selectors[] = $selector;
}
$selector = WP_CSS_Complex_Selector::parse( $input, $offset );
if ( null === $selector ) {
return null;
}
if ( count( $selectors ) ) {
return new WP_CSS_Selector_List( $selectors );
WP_CSS_Selector_Parser::parse_whitespace( $input, $offset );

$selectors = array( $selector );
while ( $offset < strlen( $input ) ) {
// Each loop should stop on a `,` selector list delimiter.
if ( ',' !== $input[ $offset ] ) {
return null;
}
++$offset;
WP_CSS_Selector_Parser::parse_whitespace( $input, $offset );
$selector = WP_CSS_Complex_Selector::parse( $input, $offset );
if ( null === $selector ) {
return null;
}
$selectors[] = $selector;
WP_CSS_Selector_Parser::parse_whitespace( $input, $offset );
}
return null;

return new WP_CSS_Selector_List( $selectors );
}
}

Expand All @@ -145,7 +155,7 @@ public static function parse( string $input, int &$offset );
abstract class WP_CSS_Selector_Parser implements IWP_CSS_Selector_Parser {
const UTF8_MAX_CODEPOINT_VALUE = 0x10FFFF;

protected static function parse_whitespace( string $input, int &$offset ): bool {
public static function parse_whitespace( string $input, int &$offset ): bool {
$length = strspn( $input, " \t\r\n\f", $offset );
$advanced = $length > 0;
$offset += $length;
Expand Down Expand Up @@ -938,35 +948,38 @@ public static function parse( string $input, int &$offset ): ?self {

$found_whitespace = self::parse_whitespace( $input, $updated_offset );
while ( $updated_offset < strlen( $input ) ) {
switch ( $input[ $updated_offset ] ) {
case self::COMBINATOR_CHILD:
case self::COMBINATOR_NEXT_SIBLING:
case self::COMBINATOR_SUBSEQUENT_SIBLING:
if (
self::COMBINATOR_CHILD === $input[ $updated_offset ] ||
self::COMBINATOR_NEXT_SIBLING === $input[ $updated_offset ] ||
self::COMBINATOR_SUBSEQUENT_SIBLING === $input[ $updated_offset ]
) {
$combinator = $input[ $updated_offset ];
++$updated_offset;
self::parse_whitespace( $input, $updated_offset );
break;

default:
/*
* Whitespace is a descendant combinator.
* Either whitespace was found and we're on a selector,
* or we've failed to find any combinator and parsing is complete.
*/
if ( ! $found_whitespace ) {
break 2;
}
$combinator = self::COMBINATOR_DESCENDANT;
// Failure to find a selector here is a parse error
$selector = WP_CSS_Selector::parse( $input, $updated_offset );
// Failure to find a selector is a parse error.
if ( null === $selector ) {
return null;
}
$selectors[] = $combinator;
$selectors[] = $selector;
} elseif ( ! $found_whitespace ) {
break;
} else {

/*
* Whitespace is ambiguous, it could be a descendant combinator or
* insignificant whitespace.
*/
$selector = WP_CSS_Selector::parse( $input, $updated_offset );
if ( null === $selector ) {
break;
}
$selectors[] = self::COMBINATOR_DESCENDANT;
$selectors[] = $selector;
}
// Here we've found a combinator and need another selector.
$selector = WP_CSS_Selector::parse( $input, $updated_offset );
// Failure to find a selector is a parse error.
if ( null === $selector ) {
return null;
}
$selectors[] = $combinator;
$selectors[] = $selector;
$found_whitespace = self::parse_whitespace( $input, $updated_offset );
}
$offset = $updated_offset;
Expand Down
67 changes: 65 additions & 2 deletions tests/phpunit/tests/html-api/wpCssSelectors.php
Original file line number Diff line number Diff line change
Expand Up @@ -357,15 +357,24 @@ public function test_parse_selector() {
$this->assertSame( ' > .child', substr( $input, $offset ) );
}

/**
* @ticket TBD
*/
public function test_parse_empty_selector() {
$input = '';
$offset = 0;
$result = WP_CSS_Selector::parse( $input, $offset );
$this->assertNull( $result );
}

/**
* @ticket TBD
*/
public function test_parse_complex_selector() {
$input = 'el.foo#bar[baz=quux] > .child, rest';
$input = 'el.foo#bar[baz=quux] > .child , rest';
$offset = 0;
$sel = WP_CSS_Complex_Selector::parse( $input, $offset );

var_dump( $sel );
$this->assertSame( 3, count( $sel->selectors ) );
$this->assertNotNull( $sel->selectors[0]->type_selector );
$this->assertSame( 3, count( $sel->selectors[0]->subclass_selectors ) );
Expand All @@ -376,4 +385,58 @@ public function test_parse_complex_selector() {

$this->assertSame( ', rest', substr( $input, $offset ) );
}

/**
* @ticket TBD
*/
public function test_parse_invalid_complex_selector() {
$input = 'el.foo#bar[baz=quux] > , rest';
$offset = 0;
$result = WP_CSS_Complex_Selector::parse( $input, $offset );
$this->assertNull( $result );
}

public function test_parse_empty_complex_selector() {
$input = '';
$offset = 0;
$result = WP_CSS_Complex_Selector::parse( $input, $offset );
$this->assertNull( $result );
}


/**
* @ticket TBD
*/
public function test_parse_selector_list() {
$input = 'el.foo#bar[baz=quux] .descendent , rest';
$result = WP_CSS_Selector_List::from_selectors( $input );
$this->assertNotNull( $result );
}

/**
* @ticket TBD
*/
public function test_parse_invalid_selector_list() {
$input = 'el,,';
$result = WP_CSS_Selector_List::from_selectors( $input );
$this->assertNull( $result );
}

/**
* @ticket TBD
*/
public function test_parse_invalid_selector_list2() {
$input = 'el!';
$result = WP_CSS_Selector_List::from_selectors( $input );
$this->assertNull( $result );
}

/**
* @ticket TBD
*/
public function test_parse_empty_selector_list() {
$input = " \t \t\n\r\f";
$result = WP_CSS_Selector_List::from_selectors( $input );
$this->assertNull( $result );
}
}

0 comments on commit 370539b

Please sign in to comment.