diff --git a/functionMap.php b/functionMap.php index 6fe36ba..acbcca6 100644 --- a/functionMap.php +++ b/functionMap.php @@ -361,11 +361,12 @@ 'WP_Object_Cache::delete' => [null, 'deprecated' => 'false'], 'WP_Dependencies::$groups' => [null, '@phpstan-var' => 'array'], 'WP_Dependencies::get_etag' => ['non-falsy-string'], - 'WP_Dependencies::query' => ["(\$handle is not non-empty-string ? false : (\$status is not TStatus ? false : (\$status is 'registered'|'scripts' ? _WP_Dependency|false : bool)))", '@phpstan-template TStatus' => "'registered'|'scripts'|'enqueued'|'queued'|'to_do'|'to_print'|'done'|'printed'"], + 'WP_Dependencies::query' => ["(\$handle is not non-empty-string ? false : (\$status is not TStatus ? false : (\$status is 'registered'|'scripts' ? _WP_Dependency|false : bool)))", '@phpstan-template TStatus' => "of 'registered'|'scripts'|'enqueued'|'queued'|'to_do'|'to_print'|'done'|'printed'"], 'WP_Http::get' => [$httpReturnType], 'WP_Http::head' => [$httpReturnType], 'WP_Http::post' => [$httpReturnType], 'WP_Http::request' => [$httpReturnType], + 'WP_Image_Editor::get_output_format' => ['array{string|null, string|false, string}'], 'WP_List_Table::set_pagination_args' => ['void', 'args' => 'array{total_items?: int, total_pages?: int, per_page?: int}'], 'WP_Locale::$word_count_type' => [null, '@phpstan-var' => "'characters_excluding_spaces'|'characters_including_spaces'|'words'"], 'WP_Locale::get_word_count_type' => ["'characters_excluding_spaces'|'characters_including_spaces'|'words'"], diff --git a/src/Visitor.php b/src/Visitor.php index f15fc5a..affe37a 100644 --- a/src/Visitor.php +++ b/src/Visitor.php @@ -299,6 +299,51 @@ private function getVariableNamesFromTags(array $tags): array return $names; } + /** + * @param array<\phpDocumentor\Reflection\DocBlock\Tag> $tags + * @return list + */ + private static function getTemplateNamesFromTags(array $tags): array + { + $names = []; + + foreach ($tags as $tag) { + if (! ($tag instanceof Generic)) { + continue; + } + + if (preg_match('#^\s*(\S+)#', (string)$tag, $matches) !== 1) { + continue; + } + + $names[] = $matches[1]; + } + + return $names; + } + + /** + * @return list + */ + private function getParamNamesFromMap(string $symbolName): array + { + if (! array_key_exists($symbolName, $this->functionMap)) { + return []; + } + + $names = []; + + foreach (array_keys($this->functionMap[$symbolName]) as $paramName) { + if (! is_string($paramName) || str_starts_with($paramName, '@')) { + continue; + } + + $names[] = $paramName; + } + + return $names; + } + private function addTags(string $name, Doc $docComment): ?Doc { $additions = $this->additionalTags[$name] ?? []; @@ -311,6 +356,15 @@ private function addTags(string $name, Doc $docComment): ?Doc } $additions = $this->discoverInheritedArgs($docblock, $additions); + $mapParamNames = $this->getParamNamesFromMap($name); + + // A parameter type from the function map replaces the one generated from the hash notation. + $additions = array_filter( + $additions, + static function (WordPressTag $tag) use ($mapParamNames): bool { + return $tag->tag !== '@phpstan-param' || ! in_array($tag->name, $mapParamNames, true); + } + ); /** @var list $additionStrings */ $additionStrings = array_map( @@ -552,6 +606,43 @@ private function addStringTags(string $name, Doc $docComment): ?Doc $additions = $this->additionalTagStrings[$name]; $docCommentText = $docComment->getText(); + try { + $docblock = $this->docBlockFactory->create($docCommentText); + } catch (\RuntimeException | \InvalidArgumentException $e) { + return null; + } + + if (count($docblock->getTagsByName('phpstan-return')) > 0) { + $additions = array_filter( + $additions, + static function (string $tag): bool { + return ! str_starts_with($tag, '@phpstan-return '); + } + ); + } + + $existingParamNames = $this->getVariableNamesFromTags($docblock->getTagsByName('phpstan-param')); + $existingTemplateNames = self::getTemplateNamesFromTags($docblock->getTagsByName('phpstan-template')); + + $additions = array_filter( + $additions, + static function (string $tag) use ($existingParamNames, $existingTemplateNames): bool { + if (preg_match('#^@phpstan-param\s.*\$([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)$#s', $tag, $matches) === 1) { + return ! in_array($matches[1], $existingParamNames, true); + } + + if (preg_match('#^@phpstan-template\s+(\S+)#', $tag, $matches) === 1) { + return ! in_array($matches[1], $existingTemplateNames, true); + } + + return true; + } + ); + + if (count($additions) === 0) { + return null; + } + $newDocComment = sprintf( "%s\n * %s\n */", substr($docCommentText, 0, -self::WP_INDENT_SIZE), @@ -597,7 +688,11 @@ private function getAdditionFromParam(Param $tag): ?WordPressTag // It's common for an args parameter to accept a query var string or array with `string|array`. // Remove the accepted string type for these so we get the strongest typing we can manage. - $tagVariableType = str_replace(['|string', 'string|'], '', $tagVariableType); + $members = WordPressTag::getUnionMembers($tagVariableType); + + if ($members !== null && count($members) > 1) { + $tagVariableType = implode('|', array_diff($members, ['string'])); + } $tag = new WordPressTag(); $tag->tag = '@phpstan-param'; @@ -734,37 +829,41 @@ private static function getTypeNameFromType(Type $tagVariableType): ?string private static function getTypeNameFromString(string $tagVariable): ?string { - // PHPStan doesn't support typed array shapes (`int[]{...}`) so replace - // typed arrays such as `int[]` with `array`. - $tagVariableType = preg_replace('#[a-zA-Z0-9_]+\[\]#', 'array', $tagVariable); + $members = WordPressTag::getUnionMembers($tagVariable); - if ($tagVariableType === null) { + if ($members === null) { return null; } - $tagVariableType = str_replace( - [ - 'stdClass', - '\\object', - ], - 'object', - $tagVariableType - ); + $members = array_map( + static function (string $member): string { + // PHPStan doesn't support typed array shapes (`int[]{...}`) so replace + // typed arrays such as `int[]` with `array`. + if (preg_match('#^[a-zA-Z0-9_\\\\]+(?:\[\])+$#', $member) === 1) { + return 'array'; + } - $supportedTypes = [ - 'object', - 'array', - ]; + if (in_array(ltrim($member, '\\'), ['stdClass', 'object'], true)) { + return 'object'; + } - foreach ($supportedTypes as $supportedType) { - if (! str_contains($tagVariableType, "{$supportedType}|")) { - continue; - } - // Move the type that uses the hash notation to the end of union types so the shape works. - $tagVariableType = sprintf('%s|%s', str_replace("{$supportedType}|", '', $tagVariableType), $supportedType); + return $member; + }, + $members + ); + + // Move the type that uses the hash notation to the end of union types so the shape works. + foreach (['object', 'array'] as $supportedType) { + $hashTypes = array_filter( + $members, + static function (string $member) use ($supportedType): bool { + return $member === $supportedType || str_starts_with($member, "{$supportedType}<"); + } + ); + $members = array_merge(array_diff_key($members, $hashTypes), $hashTypes); } - return $tagVariableType; + return implode('|', $members); } /** diff --git a/src/WordPressTag.php b/src/WordPressTag.php index 2d53a35..4e291aa 100644 --- a/src/WordPressTag.php +++ b/src/WordPressTag.php @@ -39,12 +39,18 @@ public function format(): array $strings = []; $childStrings = []; $level = 1; + $children = $this->children; + $listDepth = 0; if (! $this->isArrayShape()) { $level = 0; + $children = self::getListElementChildren($this, $listDepth); } - foreach ($this->children as $child) { + $listOpen = str_repeat('array', $listDepth); + + foreach ($children as $child) { $childStrings = array_merge($childStrings, $child->format($level)); } @@ -55,17 +61,28 @@ public function format(): array $name = $this->name !== null ? " \${$this->name}" : ''; if ($this->isArrayShape()) { + // PHPStan doesn't support shapes of generic arrays (`array{...}`), so turn + // `array` into an unsealed shape whose other elements are typed `K => V`. + $type = $this->type; + + if (preg_match('#^(?(?:.*\|)?)array(?<(?:[^<>]++|(?&generic))*>)$#s', $type, $matches) === 1) { + $type = "{$matches['union']}array"; + $childStrings[] = sprintf(' ...%s,', $matches['generic']); + } + $strings[] = sprintf( '%s %s{', $this->tag, - $this->type + $type ); } else { - if (! $this->children[0]->hasChildren()) { + if (! $children[0]->hasChildren()) { $strings[] = sprintf( - '%s array%s', + '%s array%s', $this->tag, - $this->type, + $listOpen, + $listDepth === 0 ? $this->type : $children[0]->type, + $listClose, $name ); @@ -73,9 +90,10 @@ public function format(): array } $strings[] = sprintf( - '%s %stag, - $this->type + $this->type, + $listOpen ); } @@ -88,8 +106,51 @@ public function format(): array $strings[] = $this->isArrayShape() ? sprintf('}%s%s', $name, $description) - : sprintf('}>%s%s', $name, $description); + : sprintf('}%s>%s%s', $listClose, $name, $description); return $strings; } + + /** + * Unwraps lists of lists (`@type array ...$0 {` nested in `@type array ...$0 {`), + * counting the unwrapped lists in `$depth`. + * + * @return list<\PhpStubs\WordPress\Core\WordPressArg> + */ + private static function getListElementChildren(WithChildren $node, int &$depth): array + { + $children = $node->children; + + if (count($children) !== 1 || $children[0]->name !== null || ! $children[0]->hasChildren() || $children[0]->isArrayShape() || $children[0]->isMixedShape()) { + return $children; + } + + $depth += 1; + + return self::getListElementChildren($children[0], $depth); + } + + /** + * Splits a type into the members of its top-level union, keeping the unions + * nested in generics, shapes and callables together. + * + * @return list|null + */ + public static function getUnionMembers(string $type): ?array + { + $member = '(?:[^|<>{}()\'"]++|\'[^\']*\'|"[^"]*"|(?[<{(](?:[^<>{}()\'"]++|\'[^\']*\'|"[^"]*"|(?&bracket))*[>})]))++'; + + if (preg_match_all("#{$member}#", $type, $matches) === false) { + return null; + } + + return array_values( + array_filter( + array_map('trim', $matches[0]), + static function (string $member): bool { + return $member !== ''; + } + ) + ); + } } diff --git a/tests/ParameterTypeTest.php b/tests/ParameterTypeTest.php index 6309311..989d2e6 100644 --- a/tests/ParameterTypeTest.php +++ b/tests/ParameterTypeTest.php @@ -450,4 +450,17 @@ public function testWpUploadBits(): void ] ); } + + public function testWpEnqueueScriptModule(): void + { + $this->analyse( + __DIR__ . '/data/param/wp-enqueue-script-module.php', + [ + ['Parameter #5 $args of function wp_enqueue_script_module expects array{in_footer?: bool, fetchpriority?: \'auto\'|\'high\'|\'low\', ...}, array{in_footer: \'yes\'} given.', 10], + ['Parameter #5 $args of function wp_enqueue_script_module expects array{in_footer?: bool, fetchpriority?: \'auto\'|\'high\'|\'low\', ...}, array{fetchpriority: \'urgent\'} given.', 11], + ['Parameter #5 $args of function wp_enqueue_script_module expects array{in_footer?: bool, fetchpriority?: \'auto\'|\'high\'|\'low\', ...}, array{other: 1} given.', 12], + ['Parameter #5 $args of function wp_enqueue_script_module expects array{in_footer?: bool, fetchpriority?: \'auto\'|\'high\'|\'low\', ...}, array{1: true} given.', 13], + ] + ); + } } diff --git a/tests/VisitorTest.php b/tests/VisitorTest.php index a36c7b5..328bf4b 100644 --- a/tests/VisitorTest.php +++ b/tests/VisitorTest.php @@ -67,6 +67,33 @@ function wpstubs_test_connector_with_phpstan_return( string $id ): ?array { ); } + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testMapReturnDoesNotOverrideExistingReturn(): void + { + $code = <<<'PHP' + $args { + * Optional. Arguments. + * + * @type bool $in_footer Whether to print in the footer. + * @type 'auto'|'low'|'high' $fetchpriority Fetch priority. + * } + */ + function wpstubs_test_generic_shape($args = []) {} + PHP; + + $stubs = self::generateStubs($code); + + self::assertStringContainsString( + "@phpstan-param array{\n * in_footer?: bool,\n * fetchpriority?: 'auto'|'low'|'high',\n * ...,\n * } \$args", + $stubs + ); + } + + /** + * A list of lists of array shapes is formatted as nested generic arrays. + */ + public function testListOfListsOfArrayShapes(): void + { + $code = <<<'PHP' + > \$fonts", + $stubs + ); + } + + /** + * A parameter type from the function map replaces the one generated from the hash notation. + * + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testMapParamReplacesGeneratedParam(): void + { + $code = <<<'PHP' + 'yes']); // incorrect +wp_enqueue_script_module('id', '', [], false, ['fetchpriority' => 'urgent']); // incorrect +wp_enqueue_script_module('id', '', [], false, ['other' => 1]); // incorrect +wp_enqueue_script_module('id', '', [], false, [1 => true]); // incorrect + +// Correct usage +wp_enqueue_script_module('id'); +wp_enqueue_script_module('id', '', [], false, []); +wp_enqueue_script_module('id', '', [], false, ['in_footer' => true, 'fetchpriority' => 'low']); +wp_enqueue_script_module('id', '', [], false, ['other' => 'value', 'flag' => false]); diff --git a/tests/data/return/wp-dependencies.php b/tests/data/return/wp-dependencies.php index 9213847..14c06a4 100644 --- a/tests/data/return/wp-dependencies.php +++ b/tests/data/return/wp-dependencies.php @@ -32,3 +32,6 @@ assertType('bool', Faker::wpScripts()->query(Faker::nonEmptyString(), 'enqueued')); assertType('_WP_Dependency|false', Faker::wpStyles()->query(Faker::nonEmptyString(), 'registered')); assertType('bool', Faker::wpStyles()->query(Faker::nonEmptyString(), 'enqueued')); + +// Always false if $status is not a known status +assertType('false', Faker::wpDependencies()->query(Faker::nonEmptyString(), 'unknown')); diff --git a/tests/data/return/wp-image-editor.php b/tests/data/return/wp-image-editor.php new file mode 100644 index 0000000..f6d3b03 --- /dev/null +++ b/tests/data/return/wp-image-editor.php @@ -0,0 +1,18 @@ +get_output_format()); + assertType('array{string|null, string|false, string}', $this->get_output_format('image.jpg', 'image/webp')); + } +} diff --git a/wordpress-stubs.php b/wordpress-stubs.php index 9565127..393afed 100644 --- a/wordpress-stubs.php +++ b/wordpress-stubs.php @@ -42457,7 +42457,7 @@ protected function recurse_deps($queue, $handle) * @param string $handle Name of the item. Should be unique. * @param string $status Optional. Status of the item to query. Default 'registered'. * @return bool|_WP_Dependency Found, or object Item data. - * @phpstan-template TStatus 'registered'|'scripts'|'enqueued'|'queued'|'to_do'|'to_print'|'done'|'printed' + * @phpstan-template TStatus of 'registered'|'scripts'|'enqueued'|'queued'|'to_do'|'to_print'|'done'|'printed' * @phpstan-return ($handle is not non-empty-string ? false : ($status is not TStatus ? false : ($status is 'registered'|'scripts' ? _WP_Dependency|false : bool))) */ public function query($handle, $status = 'registered') @@ -45004,7 +45004,6 @@ class WP_Http * filename: string|null, * http_response: WP_HTTP_Requests_Response|null, * } - * @phpstan-return array{headers: \WpOrg\Requests\Utility\CaseInsensitiveDictionary, body: string, response: array{code: int, message: string}, cookies: array, filename: string|null, http_response: \WP_HTTP_Requests_Response}|\WP_Error */ public function request($url, $args = array()) { @@ -45784,6 +45783,7 @@ protected function get_default_quality($mime_type) * @param string $filename * @param string $mime_type * @return array { filename|null, extension, mime-type } + * @phpstan-return array{string|null, string|false, string} */ protected function get_output_format($filename = \null, $mime_type = \null) { @@ -50965,7 +50965,6 @@ public function rewind_comments() * @phpstan-return ( * $query is array{ fields: 'ids', ... } ? int[] : WP_Post[] * ) - * @phpstan-return ($query is array ? ($query is array{fields: 'id=>parent'|'ids', ...} ? array : array) : array|array) */ public function query($query) { @@ -53236,9 +53235,10 @@ class WP_Script_Modules * @type bool $in_footer Whether to print the script module in the footer. Only relevant to block themes. Default 'false'. Optional. * @type 'auto'|'low'|'high' $fetchpriority Fetch priority. Default 'auto'. Optional. * } - * @phpstan-param array{ + * @phpstan-param array{ * in_footer?: bool, * fetchpriority?: 'auto'|'low'|'high', + * ..., * } $args * @phpstan-return void */ @@ -53320,9 +53320,10 @@ public function set_in_footer(string $id, bool $in_footer): bool * @type bool $in_footer Whether to print the script module in the footer. Only relevant to block themes. Default 'false'. Optional. * @type 'auto'|'low'|'high' $fetchpriority Fetch priority. Default 'auto'. Optional. * } - * @phpstan-param array{ + * @phpstan-param array{ * in_footer?: bool, * fetchpriority?: 'auto'|'low'|'high', + * ..., * } $args * @phpstan-return void */ @@ -68846,24 +68847,22 @@ class WP_Font_Face * @param array[][] $fonts Optional. The font-families and their font variations. * See {@see wp_print_font_faces()} for the supported fields. * Default empty array. - * @phpstan-param array[], - * }> $fonts See wp_print_font_faces() + * @phpstan-param array> $fonts See wp_print_font_faces() * @phpstan-return void */ public function generate_and_print(array $fonts) @@ -107653,10 +107652,6 @@ function add_settings_section($id, $title, $callback, $page, $args = array()) * @type string $class CSS Class to be added to the `` element when the * field is output. * } - * @phpstan-param array{ - * label_for?: string, - * class?: string, - * } $args * @phpstan-param array{label_for?: string, class?: string, ...} $args * @phpstan-return void */ @@ -120906,9 +120901,6 @@ function has_term($term = '', $taxonomy = '', $post = \null) * @type string $taxonomy Taxonomy to retrieve terms for. Default 'category'. * } * @return array List of category objects. - * @phpstan-param array{ - * taxonomy?: string, - * } $args * @phpstan-param array{taxonomy?:string,...} $args * @phpstan-return ($args is array{fields: 'count', ...} ? list : ($args is array{fields: 'names'|'slugs', ...} ? list : ($args is array{fields: 'id=>name'|'id=>slug', ...} ? array : ($args is array{fields: 'id=>parent', ...} ? array : ($args is array{fields: 'ids'|'tt_ids', ...} ? list : array))))) */ @@ -129349,24 +129341,22 @@ function fetch_feed($url) * } * } * } - * @phpstan-param array[], - * }> $fonts + * @phpstan-param array> $fonts * @phpstan-return void */ function wp_print_font_faces($fonts = array()) @@ -130542,10 +130532,7 @@ function stripslashes_deep($value) * @phpstan-template T * @phpstan-param T $value * @phpstan-return (T is string ? string : T) - * @phpstan-template T - * @phpstan-param T|string $value * @phpstan-pure - * @phpstan-return ($value is string ? ($value is '' ? '' : string) : T) */ function stripslashes_from_strings_only($value) { @@ -132779,7 +132766,6 @@ function win_is_writable($path) * baseurl: non-empty-string, * } * |array{ error: non-empty-string } - * @phpstan-return array{path: string, url: string, subdir: string, basedir: string, baseurl: string, error: false|string} */ function wp_get_upload_dir() { @@ -132828,7 +132814,6 @@ function wp_get_upload_dir() * baseurl: non-empty-string, * } * |array{ error: non-empty-string } - * @phpstan-return array{path: string, url: string, subdir: string, basedir: string, baseurl: string, error: false|string} */ function wp_upload_dir($time = \null, $create_dir = \true, $refresh_cache = \false) { @@ -133158,7 +133143,6 @@ function wp_nonce_ays($action) * code?: string, * exit?: bool, * } $args - * @phpstan-return ($args is array{exit: false, ...} ? void : never) */ function wp_die($message = '', $title = '', $args = array()) { @@ -150588,7 +150572,6 @@ function auth_redirect() * as the function otherwise exits rather than returning false. * @phpstan-return ( $action is -1 ? int|false : int ) * @phpstan-param string $action - * @phpstan-return ($action is -1 ? 1|2|false : 1|2) */ function check_admin_referer($action = -1, $query_arg = '_wpnonce') { @@ -150610,7 +150593,6 @@ function check_admin_referer($action = -1, $query_arg = '_wpnonce') * as the function otherwise exits rather than returning false. * @phpstan-return ( $stop is true ? int : int|false ) * @phpstan-param string $action - * @phpstan-return ($stop is true ? 1|2 : 1|2|false) */ function check_ajax_referer($action = -1, $query_arg = \false, $stop = \true) { @@ -153294,7 +153276,6 @@ function get_post_type_object($post_type) * @return string[]|WP_Post_Type[] An array of post type names or objects. * @phpstan-return ( $output is 'names' ? string[] : WP_Post_Type[] ) * @phpstan-param 'names'|'objects' $output - * @phpstan-return ($output is 'names' ? array : array) */ function get_post_types($args = array(), $output = 'names', $operator = 'and') { @@ -154025,7 +154006,6 @@ function is_post_embeddable($post = \null) * w?: int, * year?: int, * } $args - * @phpstan-return ($args is array{fields: 'id=>parent'|'ids', ...} ? array : array) */ function get_posts($args = \null) { @@ -154298,7 +154278,6 @@ function sanitize_post($post, $context = 'display') * ) * @phpstan-template T of mixed * @phpstan-param T $value - * @phpstan-return ($field is 'ID'|'post_parent'|'menu_order' ? (T is int ? T : int) : ($field is 'ancestors' ? (T is array>|list> ? T : (T is list ? list> : array>)) : ($context is 'raw' ? T : ($context is 'attribute'|'js' ? string : ($context is 'edit' ? ($field is not 'post_content' ? string : mixed) : mixed))))) */ function sanitize_post_field($field, $value, $post_id, $context = 'display') { @@ -154823,7 +154802,6 @@ function wp_get_recent_posts($args = array(), $output = \ARRAY_A) * meta_input?: array, * page_template?: string, * } $postarr - * @phpstan-return ($wp_error is false ? int<0, max> : int<1, max>|\WP_Error) */ function wp_insert_post($postarr, $wp_error = \false, $fire_after_hooks = \true) { @@ -154876,7 +154854,6 @@ function wp_insert_post($postarr, $wp_error = \false, $fire_after_hooks = \true) * meta_input?: array, * page_template?: string, * } $postarr See wp_insert_post() - * @phpstan-return ($wp_error is false ? int<0, max> : int<1, max>|\WP_Error) */ function wp_update_post($postarr = array(), $wp_error = \false, $fire_after_hooks = \true) { @@ -155367,7 +155344,6 @@ function is_local_attachment($url) * @phpstan-return ( * $wp_error is false ? int : int|WP_Error * ) - * @phpstan-return ($wp_error is false ? int<0, max> : int<1, max>|\WP_Error) */ function wp_insert_attachment($args, $file = \false, $parent_post_id = 0, $wp_error = \false, $fire_after_hooks = \true) { @@ -159447,9 +159423,10 @@ function wp_enqueue_block_support_styles($style, $priority = 10) * @type bool $prettify Whether to add new lines and indents to output. * Default to whether the `SCRIPT_DEBUG` constant is defined. * } - * @phpstan-param array{ + * @phpstan-param array{ * optimize?: bool, * prettify?: bool, + * ..., * } $options * @phpstan-return void */ @@ -159476,13 +159453,14 @@ function wp_enqueue_stored_styles($options = array()) * @type string $media The media for which this stylesheet has been defined. * @type string|null $path Absolute path to the stylesheet, so that it can potentially be inlined. * } - * @phpstan-param array|array{ + * @phpstan-param array{ * handle?: string, * src?: string|false, * deps?: string[], * ver?: string|bool|null, * media?: string, * path?: string|null, + * ..., * } $args */ function wp_enqueue_block_style($block_name, $args) @@ -159685,9 +159663,10 @@ function wp_script_modules(): \WP_Script_Modules * @type bool $in_footer Whether to print the script module in the footer. Only relevant to block themes. Default 'false'. Optional. * @type 'auto'|'low'|'high' $fetchpriority Fetch priority. Default 'auto'. Optional. * } - * @phpstan-param array{ + * @phpstan-param array{ * in_footer?: bool, * fetchpriority?: 'auto'|'low'|'high', + * ..., * } $args */ function wp_register_script_module(string $id, string $src, array $deps = array(), $version = \false, array $args = array()) @@ -159732,9 +159711,10 @@ function wp_register_script_module(string $id, string $src, array $deps = array( * @type bool $in_footer Whether to print the script module in the footer. Only relevant to block themes. Default 'false'. Optional. * @type 'auto'|'low'|'high' $fetchpriority Fetch priority. Default 'auto'. Optional. * } - * @phpstan-param array{ + * @phpstan-param array{ * in_footer?: bool, * fetchpriority?: 'auto'|'low'|'high', + * ..., * } $args */ function wp_enqueue_script_module(string $id, string $src = '', array $deps = array(), $version = \false, array $args = array()) @@ -161313,7 +161293,6 @@ function unregister_term_meta($taxonomy, $meta_key) * ) * ) * ) - * @phpstan-return ($term is 0 ? 0 : ($term is '' ? null : ($taxonomy is '' ? string|null : array{term_id: string, term_taxonomy_id: string}|null))) */ function term_exists($term, $taxonomy = '', $parent_term = \null) {