Skip to content

Commit

Permalink
HTML API: Add PHP type annotations.
Browse files Browse the repository at this point in the history
This patch adds type annotations to internal and private methods of the HTML
API and the supporting WP_Token_Map. Annotations have not been added to the
public interfaces where it would likely crash a site if called wrong.

These annotations should help avoid unnecessary type-related bugs (as have
been uncovered in earlier work adding such annotations) and provide additional
guidance to developers when interacting with these classes in an IDE.

Developed in WordPress#6753
Discussed in https://core.trac.wordpress.org/ticket/61399

Props dmsnell, jonsurrell.
See #61399.


git-svn-id: https://develop.svn.wordpress.org/trunk@58769 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
dmsnell committed Jul 19, 2024
1 parent e407bb0 commit 0b17989
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 153 deletions.
29 changes: 15 additions & 14 deletions src/wp-includes/class-wp-token-map.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ class WP_Token_Map {
*
* @return WP_Token_Map|null Token map, unless unable to create it.
*/
public static function from_array( $mappings, $key_length = 2 ) {
public static function from_array( array $mappings, int $key_length = 2 ): ?WP_Token_Map {
$map = new WP_Token_Map();
$map->key_length = $key_length;

Expand Down Expand Up @@ -328,7 +328,7 @@ public static function from_array( $mappings, $key_length = 2 ) {
foreach ( $groups as $group_key => $group ) {
usort(
$groups[ $group_key ],
static function ( $a, $b ) {
static function ( array $a, array $b ): int {
return self::longest_first_then_alphabetical( $a[0], $b[0] );
}
);
Expand Down Expand Up @@ -385,7 +385,7 @@ static function ( $a, $b ) {
*
* @return WP_Token_Map Map with precomputed data loaded.
*/
public static function from_precomputed_table( $state ) {
public static function from_precomputed_table( $state ): ?WP_Token_Map {
$has_necessary_state = isset(
$state['storage_version'],
$state['key_length'],
Expand Down Expand Up @@ -439,7 +439,7 @@ public static function from_precomputed_table( $state ) {
* @param string $case_sensitivity Optional. Pass 'ascii-case-insensitive' to ignore ASCII case when matching. Default 'case-sensitive'.
* @return bool Whether there's an entry for the given word in the map.
*/
public function contains( $word, $case_sensitivity = 'case-sensitive' ) {
public function contains( string $word, string $case_sensitivity = 'case-sensitive' ): bool {
$ignore_case = 'ascii-case-insensitive' === $case_sensitivity;

if ( $this->key_length >= strlen( $word ) ) {
Expand Down Expand Up @@ -527,7 +527,7 @@ public function contains( $word, $case_sensitivity = 'case-sensitive' ) {
*
* @return string|null Mapped value of lookup key if found, otherwise `null`.
*/
public function read_token( $text, $offset = 0, &$matched_token_byte_length = null, $case_sensitivity = 'case-sensitive' ) {
public function read_token( string $text, int $offset = 0, &$matched_token_byte_length = null, $case_sensitivity = 'case-sensitive' ): ?string {
$ignore_case = 'ascii-case-insensitive' === $case_sensitivity;
$text_length = strlen( $text );

Expand Down Expand Up @@ -571,15 +571,16 @@ public function read_token( $text, $offset = 0, &$matched_token_byte_length = nu
/**
* Finds a match for a short word at the index.
*
* @since 6.6.0.
* @since 6.6.0
*
* @param string $text String in which to search for a lookup key.
* @param int $offset Optional. How many bytes into the string where the lookup key ought to start. Default 0.
* @param int|null &$matched_token_byte_length Optional. Holds byte-length of found lookup key if matched, otherwise not set. Default null.
* @param string $case_sensitivity Optional. Pass 'ascii-case-insensitive' to ignore ASCII case when matching. Default 'case-sensitive'.
*
* @param string $text String in which to search for a lookup key.
* @param int $offset Optional. How many bytes into the string where the lookup key ought to start. Default 0.
* @param ?int &$matched_token_byte_length Optional. Holds byte-length of found lookup key if matched, otherwise not set. Default null.
* @param string $case_sensitivity Optional. Pass 'ascii-case-insensitive' to ignore ASCII case when matching. Default 'case-sensitive'.
* @return string|null Mapped value of lookup key if found, otherwise `null`.
*/
private function read_small_token( $text, $offset, &$matched_token_byte_length, $case_sensitivity = 'case-sensitive' ) {
private function read_small_token( string $text, int $offset = 0, &$matched_token_byte_length = null, $case_sensitivity = 'case-sensitive' ): ?string {
$ignore_case = 'ascii-case-insensitive' === $case_sensitivity;
$small_length = strlen( $this->small_words );
$search_text = substr( $text, $offset, $this->key_length );
Expand Down Expand Up @@ -634,7 +635,7 @@ private function read_small_token( $text, $offset, &$matched_token_byte_length,
*
* @return array The lookup key/substitution values as an associate array.
*/
public function to_array() {
public function to_array(): array {
$tokens = array();

$at = 0;
Expand Down Expand Up @@ -696,7 +697,7 @@ public function to_array() {
* @param string $indent Optional. Use this string for indentation, or rely on the default horizontal tab character. Default "\t".
* @return string Value which can be pasted into a PHP source file for quick loading of table.
*/
public function precomputed_php_source_table( $indent = "\t" ) {
public function precomputed_php_source_table( string $indent = "\t" ): string {
$i1 = $indent;
$i2 = $i1 . $indent;
$i3 = $i2 . $indent;
Expand Down Expand Up @@ -801,7 +802,7 @@ static function ( $match_result ) {
* @param string $b Second string to compare.
* @return int -1 or lower if `$a` is less than `$b`; 1 or greater if `$a` is greater than `$b`, and 0 if they are equal.
*/
private static function longest_first_then_alphabetical( $a, $b ) {
private static function longest_first_then_alphabetical( string $a, string $b ): int {
if ( $a === $b ) {
return 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class WP_HTML_Active_Formatting_Elements {
* @param WP_HTML_Token $token Look for this node in the stack.
* @return bool Whether the referenced node is in the stack of active formatting elements.
*/
public function contains_node( $token ) {
public function contains_node( WP_HTML_Token $token ) {
foreach ( $this->walk_up() as $item ) {
if ( $token->bookmark_name === $item->bookmark_name ) {
return true;
Expand Down Expand Up @@ -95,7 +95,7 @@ public function current_node() {
*
* @param WP_HTML_Token $token Push this node onto the stack.
*/
public function push( $token ) {
public function push( WP_HTML_Token $token ) {
/*
* > If there are already three elements in the list of active formatting elements after the last marker,
* > if any, or anywhere in the list if there are no markers, that have the same tag name, namespace, and
Expand All @@ -119,7 +119,7 @@ public function push( $token ) {
* @param WP_HTML_Token $token Remove this node from the stack, if it's there already.
* @return bool Whether the node was found and removed from the stack of active formatting elements.
*/
public function remove_node( $token ) {
public function remove_node( WP_HTML_Token $token ) {
foreach ( $this->walk_up() as $position_from_end => $item ) {
if ( $token->bookmark_name !== $item->bookmark_name ) {
continue;
Expand Down
10 changes: 5 additions & 5 deletions src/wp-includes/html-api/class-wp-html-decoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class WP_HTML_Decoder {
* Default 'case-sensitive'.
* @return bool Whether the attribute value starts with the given string.
*/
public static function attribute_starts_with( $haystack, $search_text, $case_sensitivity = 'case-sensitive' ) {
public static function attribute_starts_with( $haystack, $search_text, $case_sensitivity = 'case-sensitive' ): bool {
$search_length = strlen( $search_text );
$loose_case = 'ascii-case-insensitive' === $case_sensitivity;
$haystack_end = strlen( $haystack );
Expand Down Expand Up @@ -90,7 +90,7 @@ public static function attribute_starts_with( $haystack, $search_text, $case_sen
* @param string $text Text containing raw and non-decoded text node to decode.
* @return string Decoded UTF-8 value of given text node.
*/
public static function decode_text_node( $text ) {
public static function decode_text_node( $text ): string {
return static::decode( 'data', $text );
}

Expand All @@ -110,7 +110,7 @@ public static function decode_text_node( $text ) {
* @param string $text Text containing raw and non-decoded attribute value to decode.
* @return string Decoded UTF-8 value of given attribute value.
*/
public static function decode_attribute( $text ) {
public static function decode_attribute( $text ): string {
return static::decode( 'attribute', $text );
}

Expand All @@ -133,7 +133,7 @@ public static function decode_attribute( $text ) {
* @param string $text Text document containing span of text to decode.
* @return string Decoded UTF-8 string.
*/
public static function decode( $context, $text ) {
public static function decode( $context, $text ): string {
$decoded = '';
$end = strlen( $text );
$at = 0;
Expand Down Expand Up @@ -421,7 +421,7 @@ public static function read_character_reference( $context, $text, $at = 0, &$mat
* @param int $code_point Which code point to convert.
* @return string Converted code point, or `�` if invalid.
*/
public static function code_point_to_utf8_bytes( $code_point ) {
public static function code_point_to_utf8_bytes( $code_point ): string {
// Pre-check to ensure a valid code point.
if (
$code_point <= 0 ||
Expand Down
42 changes: 21 additions & 21 deletions src/wp-includes/html-api/class-wp-html-open-elements.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class WP_HTML_Open_Elements {
*
* @since 6.6.0
*
* @var Closure
* @var Closure|null
*/
private $pop_handler = null;

Expand All @@ -69,7 +69,7 @@ class WP_HTML_Open_Elements {
*
* @since 6.6.0
*
* @var Closure
* @var Closure|null
*/
private $push_handler = null;

Expand All @@ -83,7 +83,7 @@ class WP_HTML_Open_Elements {
*
* @param Closure $handler The handler function.
*/
public function set_pop_handler( Closure $handler ) {
public function set_pop_handler( Closure $handler ): void {
$this->pop_handler = $handler;
}

Expand All @@ -97,7 +97,7 @@ public function set_pop_handler( Closure $handler ) {
*
* @param Closure $handler The handler function.
*/
public function set_push_handler( Closure $handler ) {
public function set_push_handler( Closure $handler ): void {
$this->push_handler = $handler;
}

Expand All @@ -109,7 +109,7 @@ public function set_push_handler( Closure $handler ) {
* @param WP_HTML_Token $token Look for this node in the stack.
* @return bool Whether the referenced node is in the stack of open elements.
*/
public function contains_node( $token ) {
public function contains_node( WP_HTML_Token $token ): bool {
foreach ( $this->walk_up() as $item ) {
if ( $token->bookmark_name === $item->bookmark_name ) {
return true;
Expand All @@ -126,7 +126,7 @@ public function contains_node( $token ) {
*
* @return int How many node are in the stack of open elements.
*/
public function count() {
public function count(): int {
return count( $this->stack );
}

Expand All @@ -138,7 +138,7 @@ public function count() {
*
* @return WP_HTML_Token|null Last node in the stack of open elements, if one exists, otherwise null.
*/
public function current_node() {
public function current_node(): ?WP_HTML_Token {
$current_node = end( $this->stack );

return $current_node ? $current_node : null;
Expand Down Expand Up @@ -197,7 +197,7 @@ public function current_node_is( string $identity ): bool {
* @param string[] $termination_list List of elements that terminate the search.
* @return bool Whether the element was found in a specific scope.
*/
public function has_element_in_specific_scope( $tag_name, $termination_list ) {
public function has_element_in_specific_scope( string $tag_name, $termination_list ): bool {
foreach ( $this->walk_up() as $node ) {
if ( $node->node_name === $tag_name ) {
return true;
Expand Down Expand Up @@ -233,7 +233,7 @@ public function has_element_in_specific_scope( $tag_name, $termination_list ) {
* @param string $tag_name Name of tag to check.
* @return bool Whether given element is in scope.
*/
public function has_element_in_scope( $tag_name ) {
public function has_element_in_scope( string $tag_name ): bool {
return $this->has_element_in_specific_scope(
$tag_name,
array(
Expand All @@ -260,7 +260,7 @@ public function has_element_in_scope( $tag_name ) {
* @param string $tag_name Name of tag to check.
* @return bool Whether given element is in scope.
*/
public function has_element_in_list_item_scope( $tag_name ) {
public function has_element_in_list_item_scope( string $tag_name ): bool {
return $this->has_element_in_specific_scope(
$tag_name,
array(
Expand All @@ -281,7 +281,7 @@ public function has_element_in_list_item_scope( $tag_name ) {
* @param string $tag_name Name of tag to check.
* @return bool Whether given element is in scope.
*/
public function has_element_in_button_scope( $tag_name ) {
public function has_element_in_button_scope( string $tag_name ): bool {
return $this->has_element_in_specific_scope( $tag_name, array( 'BUTTON' ) );
}

Expand All @@ -297,7 +297,7 @@ public function has_element_in_button_scope( $tag_name ) {
* @param string $tag_name Name of tag to check.
* @return bool Whether given element is in scope.
*/
public function has_element_in_table_scope( $tag_name ) {
public function has_element_in_table_scope( string $tag_name ): bool {
throw new WP_HTML_Unsupported_Exception( 'Cannot process elements depending on table scope.' );

return false; // The linter requires this unreachable code until the function is implemented and can return.
Expand All @@ -323,7 +323,7 @@ public function has_element_in_table_scope( $tag_name ) {
* @param string $tag_name Name of tag to check.
* @return bool Whether the given element is in SELECT scope.
*/
public function has_element_in_select_scope( $tag_name ) {
public function has_element_in_select_scope( string $tag_name ): bool {
foreach ( $this->walk_up() as $node ) {
if ( $node->node_name === $tag_name ) {
return true;
Expand All @@ -349,7 +349,7 @@ public function has_element_in_select_scope( $tag_name ) {
*
* @return bool Whether a P is in BUTTON scope.
*/
public function has_p_in_button_scope() {
public function has_p_in_button_scope(): bool {
return $this->has_p_in_button_scope;
}

Expand All @@ -362,7 +362,7 @@ public function has_p_in_button_scope() {
*
* @return bool Whether a node was popped off of the stack.
*/
public function pop() {
public function pop(): bool {
$item = array_pop( $this->stack );
if ( null === $item ) {
return false;
Expand All @@ -387,7 +387,7 @@ public function pop() {
* @param string $tag_name Name of tag that needs to be popped off of the stack of open elements.
* @return bool Whether a tag of the given name was found and popped off of the stack of open elements.
*/
public function pop_until( $tag_name ) {
public function pop_until( string $tag_name ): bool {
foreach ( $this->walk_up() as $item ) {
if ( 'context-node' === $item->bookmark_name ) {
return true;
Expand Down Expand Up @@ -419,7 +419,7 @@ public function pop_until( $tag_name ) {
*
* @param WP_HTML_Token $stack_item Item to add onto stack.
*/
public function push( $stack_item ) {
public function push( WP_HTML_Token $stack_item ): void {
$this->stack[] = $stack_item;
$this->after_element_push( $stack_item );
}
Expand All @@ -432,7 +432,7 @@ public function push( $stack_item ) {
* @param WP_HTML_Token $token The node to remove from the stack of open elements.
* @return bool Whether the node was found and removed from the stack of open elements.
*/
public function remove_node( $token ) {
public function remove_node( WP_HTML_Token $token ): bool {
if ( 'context-node' === $token->bookmark_name ) {
return false;
}
Expand Down Expand Up @@ -502,7 +502,7 @@ public function walk_down() {
* @param WP_HTML_Token|null $above_this_node Optional. Start traversing above this node,
* if provided and if the node exists.
*/
public function walk_up( $above_this_node = null ) {
public function walk_up( ?WP_HTML_Token $above_this_node = null ) {
$has_found_node = null === $above_this_node;

for ( $i = count( $this->stack ) - 1; $i >= 0; $i-- ) {
Expand Down Expand Up @@ -534,7 +534,7 @@ public function walk_up( $above_this_node = null ) {
*
* @param WP_HTML_Token $item Element that was added to the stack of open elements.
*/
public function after_element_push( $item ) {
public function after_element_push( WP_HTML_Token $item ): void {
/*
* When adding support for new elements, expand this switch to trap
* cases where the precalculated value needs to change.
Expand Down Expand Up @@ -567,7 +567,7 @@ public function after_element_push( $item ) {
*
* @param WP_HTML_Token $item Element that was removed from the stack of open elements.
*/
public function after_element_pop( $item ) {
public function after_element_pop( WP_HTML_Token $item ): void {
/*
* When adding support for new elements, expand this switch to trap
* cases where the precalculated value needs to change.
Expand Down
4 changes: 2 additions & 2 deletions src/wp-includes/html-api/class-wp-html-processor-state.php
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ class WP_HTML_Processor_State {
*
* @var WP_HTML_Open_Elements
*/
public $stack_of_open_elements = null;
public $stack_of_open_elements;

/**
* Tracks open formatting elements, used to handle mis-nested formatting element tags.
Expand All @@ -346,7 +346,7 @@ class WP_HTML_Processor_State {
*
* @var WP_HTML_Active_Formatting_Elements
*/
public $active_formatting_elements = null;
public $active_formatting_elements;

/**
* Refers to the currently-matched tag, if any.
Expand Down
Loading

0 comments on commit 0b17989

Please sign in to comment.