基础代码
This commit is contained in:
Vendored
+1046
File diff suppressed because it is too large
Load Diff
Vendored
+187
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
/**
|
||||
* WordPress Coding Standard.
|
||||
*
|
||||
* @package WPCS\WordPressCodingStandards
|
||||
* @link https://github.com/WordPress/WordPress-Coding-Standards
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace WordPressCS\WordPress\Sniffs\NamingConventions;
|
||||
|
||||
use PHP_CodeSniffer\Standards\PEAR\Sniffs\NamingConventions\ValidFunctionNameSniff as PHPCS_PEAR_ValidFunctionNameSniff;
|
||||
use PHP_CodeSniffer\Files\File;
|
||||
use WordPressCS\WordPress\Sniff;
|
||||
|
||||
/**
|
||||
* Enforces WordPress function name and method name format, based upon Squiz code.
|
||||
*
|
||||
* @link https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#naming-conventions
|
||||
*
|
||||
* @package WPCS\WordPressCodingStandards
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @since 0.13.0 Class name changed: this class is now namespaced.
|
||||
* @since 2.0.0 The `get_name_suggestion()` method has been moved to the
|
||||
* WordPress native `Sniff` base class as `get_snake_case_name_suggestion()`.
|
||||
* @since 2.2.0 Will now ignore functions and methods which are marked as @deprecated.
|
||||
*
|
||||
* Last synced with parent class December 2018 up to commit ee167761d7756273b8ad0ad68bf3db1f2c211bb8.
|
||||
* @link https://github.com/squizlabs/PHP_CodeSniffer/blob/master/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php
|
||||
*
|
||||
* {@internal While this class extends the PEAR parent, it does not actually use the checks
|
||||
* contained in the parent. It only uses the properties and the token registration from the parent.}}
|
||||
*/
|
||||
class ValidFunctionNameSniff extends PHPCS_PEAR_ValidFunctionNameSniff {
|
||||
|
||||
/**
|
||||
* Processes the tokens outside the scope.
|
||||
*
|
||||
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being processed.
|
||||
* @param int $stackPtr The position where this token was
|
||||
* found.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processTokenOutsideScope( File $phpcsFile, $stackPtr ) {
|
||||
|
||||
if ( Sniff::is_function_deprecated( $phpcsFile, $stackPtr ) === true ) {
|
||||
/*
|
||||
* Deprecated functions don't have to comply with the naming conventions,
|
||||
* otherwise functions deprecated in favour of a function with a compliant
|
||||
* name would still trigger an error.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
$functionName = $phpcsFile->getDeclarationName( $stackPtr );
|
||||
|
||||
if ( ! isset( $functionName ) ) {
|
||||
// Ignore closures.
|
||||
return;
|
||||
}
|
||||
|
||||
if ( '' === ltrim( $functionName, '_' ) ) {
|
||||
// Ignore special functions, like __().
|
||||
return;
|
||||
}
|
||||
|
||||
$functionNameLc = strtolower( $functionName );
|
||||
|
||||
// Is this a magic function ? I.e., it is prefixed with "__" ?
|
||||
// Outside class scope this basically just means __autoload().
|
||||
if ( 0 === strpos( $functionName, '__' ) ) {
|
||||
$magicPart = substr( $functionNameLc, 2 );
|
||||
if ( isset( $this->magicFunctions[ $magicPart ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$error = 'Function name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore';
|
||||
$errorData = array( $functionName );
|
||||
$phpcsFile->addError( $error, $stackPtr, 'FunctionDoubleUnderscore', $errorData );
|
||||
}
|
||||
|
||||
if ( $functionNameLc !== $functionName ) {
|
||||
$error = 'Function name "%s" is not in snake case format, try "%s"';
|
||||
$errorData = array(
|
||||
$functionName,
|
||||
Sniff::get_snake_case_name_suggestion( $functionName ),
|
||||
);
|
||||
$phpcsFile->addError( $error, $stackPtr, 'FunctionNameInvalid', $errorData );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the tokens within the scope.
|
||||
*
|
||||
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being processed.
|
||||
* @param int $stackPtr The position where this token was
|
||||
* found.
|
||||
* @param int $currScope The position of the current scope.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processTokenWithinScope( File $phpcsFile, $stackPtr, $currScope ) {
|
||||
|
||||
$tokens = $phpcsFile->getTokens();
|
||||
|
||||
// Determine if this is a function which needs to be examined.
|
||||
$conditions = $tokens[ $stackPtr ]['conditions'];
|
||||
end( $conditions );
|
||||
$deepestScope = key( $conditions );
|
||||
if ( $deepestScope !== $currScope ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Sniff::is_function_deprecated( $phpcsFile, $stackPtr ) === true ) {
|
||||
/*
|
||||
* Deprecated functions don't have to comply with the naming conventions,
|
||||
* otherwise functions deprecated in favour of a function with a compliant
|
||||
* name would still trigger an error.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
$methodName = $phpcsFile->getDeclarationName( $stackPtr );
|
||||
|
||||
if ( ! isset( $methodName ) ) {
|
||||
// Ignore closures.
|
||||
return;
|
||||
}
|
||||
|
||||
$className = $phpcsFile->getDeclarationName( $currScope );
|
||||
if ( isset( $className ) === false ) {
|
||||
$className = '[Anonymous Class]';
|
||||
}
|
||||
|
||||
$methodNameLc = strtolower( $methodName );
|
||||
$classNameLc = strtolower( $className );
|
||||
|
||||
// Ignore special functions.
|
||||
if ( '' === ltrim( $methodName, '_' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// PHP4 constructors are allowed to break our rules.
|
||||
if ( $methodNameLc === $classNameLc ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// PHP4 destructors are allowed to break our rules.
|
||||
if ( '_' . $classNameLc === $methodNameLc ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$extended = $phpcsFile->findExtendedClassName( $currScope );
|
||||
$interfaces = $phpcsFile->findImplementedInterfaceNames( $currScope );
|
||||
|
||||
// If this is a child class or interface implementation, it may have to use camelCase or double underscores.
|
||||
if ( ! empty( $extended ) || ! empty( $interfaces ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Is this a magic method ? I.e. is it prefixed with "__" ?
|
||||
if ( 0 === strpos( $methodName, '__' ) ) {
|
||||
$magicPart = substr( $methodNameLc, 2 );
|
||||
if ( isset( $this->magicMethods[ $magicPart ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$error = 'Method name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore';
|
||||
$errorData = array( $className . '::' . $methodName );
|
||||
$phpcsFile->addError( $error, $stackPtr, 'MethodDoubleUnderscore', $errorData );
|
||||
}
|
||||
|
||||
// Check for all lowercase.
|
||||
if ( $methodNameLc !== $methodName ) {
|
||||
$error = 'Method name "%s" in class %s is not in snake case format, try "%s"';
|
||||
$errorData = array(
|
||||
$methodName,
|
||||
$className,
|
||||
Sniff::get_snake_case_name_suggestion( $methodName ),
|
||||
);
|
||||
$phpcsFile->addError( $error, $stackPtr, 'MethodNameInvalid', $errorData );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+289
@@ -0,0 +1,289 @@
|
||||
<?php
|
||||
/**
|
||||
* WordPress Coding Standard.
|
||||
*
|
||||
* @package WPCS\WordPressCodingStandards
|
||||
* @link https://github.com/WordPress/WordPress-Coding-Standards
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace WordPressCS\WordPress\Sniffs\NamingConventions;
|
||||
|
||||
use WordPressCS\WordPress\AbstractFunctionParameterSniff;
|
||||
use PHP_CodeSniffer\Util\Tokens;
|
||||
|
||||
/**
|
||||
* Use lowercase letters in action and filter names. Separate words via underscores.
|
||||
*
|
||||
* This sniff is only testing the hook invoke functions as when using 'add_action'/'add_filter'
|
||||
* you can't influence the hook name.
|
||||
*
|
||||
* Hook names invoked with `do_action_deprecated()` and `apply_filters_deprecated()` are ignored.
|
||||
*
|
||||
* @link https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#naming-conventions
|
||||
*
|
||||
* @package WPCS\WordPressCodingStandards
|
||||
*
|
||||
* @since 0.10.0
|
||||
* @since 0.11.0 Extends the WordPressCS native `AbstractFunctionParameterSniff` class.
|
||||
* @since 0.13.0 Class name changed: this class is now namespaced.
|
||||
*/
|
||||
class ValidHookNameSniff extends AbstractFunctionParameterSniff {
|
||||
|
||||
/**
|
||||
* Additional word separators.
|
||||
*
|
||||
* This public variable allows providing additional word separators which
|
||||
* will be allowed in hook names via a property in the phpcs.xml config file.
|
||||
*
|
||||
* Example usage:
|
||||
* <rule ref="WordPress.NamingConventions.ValidHookName">
|
||||
* <properties>
|
||||
* <property name="additionalWordDelimiters" value="-"/>
|
||||
* </properties>
|
||||
* </rule>
|
||||
*
|
||||
* Provide several extra delimiters as one string:
|
||||
* <rule ref="WordPress.NamingConventions.ValidHookName">
|
||||
* <properties>
|
||||
* <property name="additionalWordDelimiters" value="-/."/>
|
||||
* </properties>
|
||||
* </rule>
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $additionalWordDelimiters = '';
|
||||
|
||||
/**
|
||||
* Regular expression to test for correct punctuation of a hook name.
|
||||
*
|
||||
* The placeholder will be replaced by potentially provided additional
|
||||
* word delimiters in the `prepare_regex()` method.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $punctuation_regex = '`[^\w%s]`';
|
||||
|
||||
/**
|
||||
* Groups of functions to restrict.
|
||||
*
|
||||
* @since 0.11.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getGroups() {
|
||||
$this->target_functions = $this->hookInvokeFunctions;
|
||||
|
||||
// No need to examine the names of deprecated hooks.
|
||||
unset(
|
||||
$this->target_functions['do_action_deprecated'],
|
||||
$this->target_functions['apply_filters_deprecated']
|
||||
);
|
||||
|
||||
return parent::getGroups();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the parameters of a matched function.
|
||||
*
|
||||
* @since 0.11.0
|
||||
*
|
||||
* @param int $stackPtr The position of the current token in the stack.
|
||||
* @param string $group_name The name of the group which was matched.
|
||||
* @param string $matched_content The token content (function name) which was matched.
|
||||
* @param array $parameters Array with information about the parameters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) {
|
||||
|
||||
$regex = $this->prepare_regex();
|
||||
|
||||
$case_errors = 0;
|
||||
$underscores = 0;
|
||||
$content = array();
|
||||
$expected = array();
|
||||
|
||||
for ( $i = $parameters[1]['start']; $i <= $parameters[1]['end']; $i++ ) {
|
||||
// Skip past comment tokens.
|
||||
if ( isset( Tokens::$commentTokens[ $this->tokens[ $i ]['code'] ] ) !== false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$content[ $i ] = $this->tokens[ $i ]['content'];
|
||||
$expected[ $i ] = $this->tokens[ $i ]['content'];
|
||||
|
||||
// Skip past potential variable array access: $var['Key'].
|
||||
if ( \T_VARIABLE === $this->tokens[ $i ]['code'] ) {
|
||||
do {
|
||||
$open_bracket = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $i + 1 ), null, true );
|
||||
if ( false === $open_bracket
|
||||
|| \T_OPEN_SQUARE_BRACKET !== $this->tokens[ $open_bracket ]['code']
|
||||
|| ! isset( $this->tokens[ $open_bracket ]['bracket_closer'] )
|
||||
) {
|
||||
continue 2;
|
||||
}
|
||||
|
||||
$i = $this->tokens[ $open_bracket ]['bracket_closer'];
|
||||
|
||||
} while ( isset( $this->tokens[ $i ] ) && $i <= $parameters[1]['end'] );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip past non-string tokens.
|
||||
if ( isset( Tokens::$stringTokens[ $this->tokens[ $i ]['code'] ] ) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$string = $this->strip_quotes( $this->tokens[ $i ]['content'] );
|
||||
|
||||
/*
|
||||
* Here be dragons - a double quoted string can contain extrapolated variables
|
||||
* which don't have to comply with these rules.
|
||||
*/
|
||||
if ( \T_DOUBLE_QUOTED_STRING === $this->tokens[ $i ]['code'] ) {
|
||||
$transform = $this->transform_complex_string( $string, $regex );
|
||||
$case_transform = $this->transform_complex_string( $string, $regex, 'case' );
|
||||
$punct_transform = $this->transform_complex_string( $string, $regex, 'punctuation' );
|
||||
} else {
|
||||
$transform = $this->transform( $string, $regex );
|
||||
$case_transform = $this->transform( $string, $regex, 'case' );
|
||||
$punct_transform = $this->transform( $string, $regex, 'punctuation' );
|
||||
}
|
||||
|
||||
if ( $string === $transform ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( \T_DOUBLE_QUOTED_STRING === $this->tokens[ $i ]['code'] ) {
|
||||
$expected[ $i ] = '"' . $transform . '"';
|
||||
} else {
|
||||
$expected[ $i ] = '\'' . $transform . '\'';
|
||||
}
|
||||
|
||||
if ( $string !== $case_transform ) {
|
||||
$case_errors++;
|
||||
}
|
||||
if ( $string !== $punct_transform ) {
|
||||
$underscores++;
|
||||
}
|
||||
}
|
||||
|
||||
$first_non_empty = $this->phpcsFile->findNext(
|
||||
Tokens::$emptyTokens,
|
||||
$parameters[1]['start'],
|
||||
( $parameters[1]['end'] + 1 ),
|
||||
true
|
||||
);
|
||||
|
||||
$data = array(
|
||||
trim( implode( '', $expected ) ),
|
||||
trim( implode( '', $content ) ),
|
||||
);
|
||||
|
||||
if ( $case_errors > 0 ) {
|
||||
$error = 'Hook names should be lowercase. Expected: %s, but found: %s.';
|
||||
$this->phpcsFile->addError( $error, $first_non_empty, 'NotLowercase', $data );
|
||||
}
|
||||
if ( $underscores > 0 ) {
|
||||
$error = 'Words in hook names should be separated using underscores. Expected: %s, but found: %s.';
|
||||
$this->phpcsFile->addWarning( $error, $first_non_empty, 'UseUnderscores', $data );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the punctuation regular expression.
|
||||
*
|
||||
* Merges the existing regular expression with potentially provided extra word delimiters to allow.
|
||||
* This is done 'late' and for each found token as otherwise inline `phpcs:set` directives
|
||||
* would be ignored.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function prepare_regex() {
|
||||
$extra = '';
|
||||
if ( '' !== $this->additionalWordDelimiters && \is_string( $this->additionalWordDelimiters ) ) {
|
||||
$extra = preg_quote( $this->additionalWordDelimiters, '`' );
|
||||
}
|
||||
|
||||
return sprintf( $this->punctuation_regex, $extra );
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform an arbitrary string to lowercase and replace punctuation and spaces with underscores.
|
||||
*
|
||||
* @param string $string The target string.
|
||||
* @param string $regex The punctuation regular expression to use.
|
||||
* @param string $transform_type Whether to a partial or complete transform.
|
||||
* Valid values are: 'full', 'case', 'punctuation'.
|
||||
* @return string
|
||||
*/
|
||||
protected function transform( $string, $regex, $transform_type = 'full' ) {
|
||||
|
||||
switch ( $transform_type ) {
|
||||
case 'case':
|
||||
return strtolower( $string );
|
||||
|
||||
case 'punctuation':
|
||||
return preg_replace( $regex, '_', $string );
|
||||
|
||||
case 'full':
|
||||
default:
|
||||
return preg_replace( $regex, '_', strtolower( $string ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a complex string which may contain variable extrapolation.
|
||||
*
|
||||
* @param string $string The target string.
|
||||
* @param string $regex The punctuation regular expression to use.
|
||||
* @param string $transform_type Whether to a partial or complete transform.
|
||||
* Valid values are: 'full', 'case', 'punctuation'.
|
||||
* @return string
|
||||
*/
|
||||
protected function transform_complex_string( $string, $regex, $transform_type = 'full' ) {
|
||||
$output = preg_split( '`([\{\}\$\[\] ])`', $string, -1, \PREG_SPLIT_DELIM_CAPTURE );
|
||||
|
||||
$is_variable = false;
|
||||
$has_braces = false;
|
||||
$braces = 0;
|
||||
|
||||
foreach ( $output as $i => $part ) {
|
||||
if ( \in_array( $part, array( '$', '{' ), true ) ) {
|
||||
$is_variable = true;
|
||||
if ( '{' === $part ) {
|
||||
$has_braces = true;
|
||||
$braces++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( true === $is_variable ) {
|
||||
if ( '[' === $part ) {
|
||||
$has_braces = true;
|
||||
$braces++;
|
||||
}
|
||||
if ( \in_array( $part, array( '}', ']' ), true ) ) {
|
||||
$braces--;
|
||||
}
|
||||
if ( false === $has_braces && ' ' === $part ) {
|
||||
$is_variable = false;
|
||||
$output[ $i ] = $this->transform( $part, $regex, $transform_type );
|
||||
}
|
||||
|
||||
if ( ( true === $has_braces && 0 === $braces ) && false === \in_array( $output[ ( $i + 1 ) ], array( '{', '[' ), true ) ) {
|
||||
$has_braces = false;
|
||||
$is_variable = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$output[ $i ] = $this->transform( $part, $regex, $transform_type );
|
||||
}
|
||||
|
||||
return implode( '', $output );
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+208
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
/**
|
||||
* WordPress Coding Standard.
|
||||
*
|
||||
* @package WPCS\WordPressCodingStandards
|
||||
* @link https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace WordPressCS\WordPress\Sniffs\NamingConventions;
|
||||
|
||||
use WordPressCS\WordPress\AbstractFunctionParameterSniff;
|
||||
use PHP_CodeSniffer\Util\Tokens;
|
||||
|
||||
/**
|
||||
* Validates post type names.
|
||||
*
|
||||
* Checks the post type slug for invalid characters, long function names
|
||||
* and reserved names.
|
||||
*
|
||||
* @link https://developer.wordpress.org/reference/functions/register_post_type/
|
||||
*
|
||||
* @package WPCS\WordPressCodingStandards
|
||||
*
|
||||
* @since 2.2.0
|
||||
*/
|
||||
class ValidPostTypeSlugSniff extends AbstractFunctionParameterSniff {
|
||||
|
||||
/**
|
||||
* Max length of a post type name is limited by the SQL field.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const POST_TYPE_MAX_LENGTH = 20;
|
||||
|
||||
/**
|
||||
* Regex that whitelists characters that can be used as the post type slug.
|
||||
*
|
||||
* @link https://developer.wordpress.org/reference/functions/register_post_type/
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const POST_TYPE_CHARACTER_WHITELIST = '/^[a-z0-9_-]+$/';
|
||||
|
||||
/**
|
||||
* Array of functions that must be checked.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @var array List of function names as keys. Value irrelevant.
|
||||
*/
|
||||
protected $target_functions = array(
|
||||
'register_post_type' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* Array of reserved post type names which can not be used by themes and plugins.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $reserved_names = array(
|
||||
'post' => true,
|
||||
'page' => true,
|
||||
'attachment' => true,
|
||||
'revision' => true,
|
||||
'nav_menu_item' => true,
|
||||
'custom_css' => true,
|
||||
'customize_changeset' => true,
|
||||
'oembed_cache' => true,
|
||||
'user_request' => true,
|
||||
'wp_block' => true,
|
||||
'action' => true,
|
||||
'author' => true,
|
||||
'order' => true,
|
||||
'theme' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* All valid tokens for in the first parameter of register_post_type().
|
||||
*
|
||||
* Set in `register()`.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $valid_tokens = array();
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register() {
|
||||
$this->valid_tokens = Tokens::$textStringTokens + Tokens::$heredocTokens + Tokens::$emptyTokens;
|
||||
return parent::register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the parameter of a matched function.
|
||||
*
|
||||
* Errors on invalid post type names when reserved keywords are used,
|
||||
* the post type is too long, or contains invalid characters.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @param int $stackPtr The position of the current token in the stack.
|
||||
* @param array $group_name The name of the group which was matched.
|
||||
* @param string $matched_content The token content (function name) which was matched.
|
||||
* @param array $parameters Array with information about the parameters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) {
|
||||
|
||||
$string_pos = $this->phpcsFile->findNext( Tokens::$textStringTokens, $parameters[1]['start'], ( $parameters[1]['end'] + 1 ) );
|
||||
$has_invalid_tokens = $this->phpcsFile->findNext( $this->valid_tokens, $parameters[1]['start'], ( $parameters[1]['end'] + 1 ), true );
|
||||
if ( false !== $has_invalid_tokens || false === $string_pos ) {
|
||||
// Check for non string based slug parameter (we cannot determine if this is valid).
|
||||
$this->phpcsFile->addWarning(
|
||||
'The post type slug is not a string literal. It is not possible to automatically determine the validity of this slug. Found: %s.',
|
||||
$stackPtr,
|
||||
'NotStringLiteral',
|
||||
array(
|
||||
$parameters[1]['raw'],
|
||||
),
|
||||
3
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$post_type = $this->strip_quotes( $this->tokens[ $string_pos ]['content'] );
|
||||
|
||||
if ( strlen( $post_type ) === 0 ) {
|
||||
// Error for using empty slug.
|
||||
$this->phpcsFile->addError(
|
||||
'register_post_type() called without a post type slug. The slug must be a non-empty string.',
|
||||
$parameters[1]['start'],
|
||||
'Empty'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
$this->tokens[ $string_pos ]['content'],
|
||||
);
|
||||
|
||||
// Warn for dynamic parts in the slug parameter.
|
||||
if ( 'T_DOUBLE_QUOTED_STRING' === $this->tokens[ $string_pos ]['type'] || ( 'T_HEREDOC' === $this->tokens[ $string_pos ]['type'] && strpos( $this->tokens[ $string_pos ]['content'], '$' ) !== false ) ) {
|
||||
$this->phpcsFile->addWarning(
|
||||
'The post type slug may, or may not, get too long with dynamic contents and could contain invalid characters. Found: %s.',
|
||||
$string_pos,
|
||||
'PartiallyDynamic',
|
||||
$data
|
||||
);
|
||||
$post_type = $this->strip_interpolated_variables( $post_type );
|
||||
}
|
||||
|
||||
if ( preg_match( self::POST_TYPE_CHARACTER_WHITELIST, $post_type ) === 0 ) {
|
||||
// Error for invalid characters.
|
||||
$this->phpcsFile->addError(
|
||||
'register_post_type() called with invalid post type %s. Post type contains invalid characters. Only lowercase alphanumeric characters, dashes, and underscores are allowed.',
|
||||
$string_pos,
|
||||
'InvalidCharacters',
|
||||
$data
|
||||
);
|
||||
}
|
||||
|
||||
if ( isset( $this->reserved_names[ $post_type ] ) ) {
|
||||
// Error for using reserved slug names.
|
||||
$this->phpcsFile->addError(
|
||||
'register_post_type() called with reserved post type %s. Reserved post types should not be used as they interfere with the functioning of WordPress itself.',
|
||||
$string_pos,
|
||||
'Reserved',
|
||||
$data
|
||||
);
|
||||
} elseif ( stripos( $post_type, 'wp_' ) === 0 ) {
|
||||
// Error for using reserved slug prefix.
|
||||
$this->phpcsFile->addError(
|
||||
'The post type passed to register_post_type() uses a prefix reserved for WordPress itself. Found: %s.',
|
||||
$string_pos,
|
||||
'ReservedPrefix',
|
||||
$data
|
||||
);
|
||||
}
|
||||
|
||||
// Error for slugs that are too long.
|
||||
if ( strlen( $post_type ) > self::POST_TYPE_MAX_LENGTH ) {
|
||||
$this->phpcsFile->addError(
|
||||
'A post type slug must not exceed %d characters. Found: %s (%d characters).',
|
||||
$string_pos,
|
||||
'TooLong',
|
||||
array(
|
||||
self::POST_TYPE_MAX_LENGTH,
|
||||
$this->tokens[ $string_pos ]['content'],
|
||||
strlen( $post_type ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+299
@@ -0,0 +1,299 @@
|
||||
<?php
|
||||
/**
|
||||
* WordPress Coding Standard.
|
||||
*
|
||||
* @package WPCS\WordPressCodingStandards
|
||||
* @link https://github.com/WordPress/WordPress-Coding-Standards
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace WordPressCS\WordPress\Sniffs\NamingConventions;
|
||||
|
||||
use PHP_CodeSniffer\Sniffs\AbstractVariableSniff as PHPCS_AbstractVariableSniff;
|
||||
use PHP_CodeSniffer\Files\File;
|
||||
use PHP_CodeSniffer\Util\Tokens;
|
||||
use WordPressCS\WordPress\Sniff;
|
||||
|
||||
/**
|
||||
* Checks the naming of variables and member variables.
|
||||
*
|
||||
* @link https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#naming-conventions
|
||||
*
|
||||
* @package WPCS\WordPressCodingStandards
|
||||
*
|
||||
* @since 0.9.0
|
||||
* @since 0.13.0 Class name changed: this class is now namespaced.
|
||||
* @since 2.0.0 - Defers to the upstream `$phpReservedVars` property.
|
||||
* - Now offers name suggestions for variables in violation.
|
||||
*
|
||||
* Last synced with base class June 2018 at commit 78ddbae97cac078f09928bf89e3ab9e53ad2ace0.
|
||||
* @link https://github.com/squizlabs/PHP_CodeSniffer/blob/master/src/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php
|
||||
*
|
||||
* @uses PHP_CodeSniffer\Sniffs\AbstractVariableSniff::$phpReservedVars
|
||||
*/
|
||||
class ValidVariableNameSniff extends PHPCS_AbstractVariableSniff {
|
||||
|
||||
/**
|
||||
* Mixed-case variables used by WordPress.
|
||||
*
|
||||
* @since 0.11.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $wordpress_mixed_case_vars = array(
|
||||
'EZSQL_ERROR' => true,
|
||||
'GETID3_ERRORARRAY' => true,
|
||||
'is_IE' => true,
|
||||
'is_IIS' => true,
|
||||
'is_macIE' => true,
|
||||
'is_NS4' => true,
|
||||
'is_winIE' => true,
|
||||
'PHP_SELF' => true,
|
||||
'post_ID' => true,
|
||||
'tag_ID' => true,
|
||||
'user_ID' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* List of member variables that can have mixed case.
|
||||
*
|
||||
* @since 0.9.0
|
||||
* @since 0.11.0 Changed from public to protected.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $whitelisted_mixed_case_member_var_names = array(
|
||||
'ID' => true,
|
||||
'comment_ID' => true,
|
||||
'comment_post_ID' => true,
|
||||
'post_ID' => true,
|
||||
'comment_author_IP' => true,
|
||||
'cat_ID' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* Custom list of properties which can have mixed case.
|
||||
*
|
||||
* @since 0.11.0
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public $customPropertiesWhitelist = array();
|
||||
|
||||
/**
|
||||
* Cache of previously added custom functions.
|
||||
*
|
||||
* Prevents having to do the same merges over and over again.
|
||||
*
|
||||
* @since 0.10.0
|
||||
* @since 0.11.0 - Name changed from $addedCustomVariables.
|
||||
* - Changed the format from simple bool to array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $addedCustomProperties = array(
|
||||
'properties' => null,
|
||||
);
|
||||
|
||||
/**
|
||||
* Processes this test, when one of its tokens is encountered.
|
||||
*
|
||||
* @param \PHP_CodeSniffer\Files\File $phpcs_file The file being scanned.
|
||||
* @param int $stack_ptr The position of the current token in the
|
||||
* stack passed in $tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processVariable( File $phpcs_file, $stack_ptr ) {
|
||||
|
||||
$tokens = $phpcs_file->getTokens();
|
||||
$var_name = ltrim( $tokens[ $stack_ptr ]['content'], '$' );
|
||||
|
||||
// If it's a php reserved var, then its ok.
|
||||
if ( isset( $this->phpReservedVars[ $var_name ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Merge any custom variables with the defaults.
|
||||
$this->mergeWhiteList();
|
||||
|
||||
// Likewise if it is a mixed-case var used by WordPress core.
|
||||
if ( isset( $this->wordpress_mixed_case_vars[ $var_name ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$obj_operator = $phpcs_file->findNext( Tokens::$emptyTokens, ( $stack_ptr + 1 ), null, true );
|
||||
if ( \T_OBJECT_OPERATOR === $tokens[ $obj_operator ]['code'] ) {
|
||||
// Check to see if we are using a variable from an object.
|
||||
$var = $phpcs_file->findNext( Tokens::$emptyTokens, ( $obj_operator + 1 ), null, true );
|
||||
if ( \T_STRING === $tokens[ $var ]['code'] ) {
|
||||
$bracket = $phpcs_file->findNext( Tokens::$emptyTokens, ( $var + 1 ), null, true );
|
||||
if ( \T_OPEN_PARENTHESIS !== $tokens[ $bracket ]['code'] ) {
|
||||
$obj_var_name = $tokens[ $var ]['content'];
|
||||
|
||||
// There is no way for us to know if the var is public or
|
||||
// private, so we have to ignore a leading underscore if there is
|
||||
// one and just check the main part of the variable name.
|
||||
$original_var_name = $obj_var_name;
|
||||
if ( '_' === substr( $obj_var_name, 0, 1 ) ) {
|
||||
$obj_var_name = substr( $obj_var_name, 1 );
|
||||
}
|
||||
|
||||
if ( ! isset( $this->whitelisted_mixed_case_member_var_names[ $obj_var_name ] ) && self::isSnakeCase( $obj_var_name ) === false ) {
|
||||
$error = 'Object property "$%s" is not in valid snake_case format, try "$%s"';
|
||||
$data = array(
|
||||
$original_var_name,
|
||||
Sniff::get_snake_case_name_suggestion( $original_var_name ),
|
||||
);
|
||||
$phpcs_file->addError( $error, $var, 'UsedPropertyNotSnakeCase', $data );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$in_class = false;
|
||||
$obj_operator = $phpcs_file->findPrevious( Tokens::$emptyTokens, ( $stack_ptr - 1 ), null, true );
|
||||
if ( \T_DOUBLE_COLON === $tokens[ $obj_operator ]['code'] || \T_OBJECT_OPERATOR === $tokens[ $obj_operator ]['code'] ) {
|
||||
// The variable lives within a class, and is referenced like
|
||||
// this: MyClass::$_variable or $class->variable.
|
||||
$in_class = true;
|
||||
}
|
||||
|
||||
// There is no way for us to know if the var is public or private,
|
||||
// so we have to ignore a leading underscore if there is one and just
|
||||
// check the main part of the variable name.
|
||||
$original_var_name = $var_name;
|
||||
if ( '_' === substr( $var_name, 0, 1 ) && true === $in_class ) {
|
||||
$var_name = substr( $var_name, 1 );
|
||||
}
|
||||
|
||||
if ( self::isSnakeCase( $var_name ) === false ) {
|
||||
if ( $in_class && ! isset( $this->whitelisted_mixed_case_member_var_names[ $var_name ] ) ) {
|
||||
$error = 'Object property "$%s" is not in valid snake_case format, try "$%s"';
|
||||
$error_name = 'UsedPropertyNotSnakeCase';
|
||||
} elseif ( ! $in_class ) {
|
||||
$error = 'Variable "$%s" is not in valid snake_case format, try "$%s"';
|
||||
$error_name = 'VariableNotSnakeCase';
|
||||
}
|
||||
|
||||
if ( isset( $error, $error_name ) ) {
|
||||
$data = array(
|
||||
$original_var_name,
|
||||
Sniff::get_snake_case_name_suggestion( $original_var_name ),
|
||||
);
|
||||
$phpcs_file->addError( $error, $stack_ptr, $error_name, $data );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes class member variables.
|
||||
*
|
||||
* @param \PHP_CodeSniffer\Files\File $phpcs_file The file being scanned.
|
||||
* @param int $stack_ptr The position of the current token in the
|
||||
* stack passed in $tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processMemberVar( File $phpcs_file, $stack_ptr ) {
|
||||
|
||||
$tokens = $phpcs_file->getTokens();
|
||||
|
||||
$var_name = ltrim( $tokens[ $stack_ptr ]['content'], '$' );
|
||||
$member_props = $phpcs_file->getMemberProperties( $stack_ptr );
|
||||
if ( empty( $member_props ) ) {
|
||||
// Couldn't get any info about this variable, which
|
||||
// generally means it is invalid or possibly has a parse
|
||||
// error. Any errors will be reported by the core, so
|
||||
// we can ignore it.
|
||||
return;
|
||||
}
|
||||
|
||||
// Merge any custom variables with the defaults.
|
||||
$this->mergeWhiteList();
|
||||
|
||||
if ( ! isset( $this->whitelisted_mixed_case_member_var_names[ $var_name ] ) && false === self::isSnakeCase( $var_name ) ) {
|
||||
$error = 'Member variable "$%s" is not in valid snake_case format, try "$%s"';
|
||||
$data = array(
|
||||
$var_name,
|
||||
Sniff::get_snake_case_name_suggestion( $var_name ),
|
||||
);
|
||||
$phpcs_file->addError( $error, $stack_ptr, 'PropertyNotSnakeCase', $data );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the variable found within a double quoted string.
|
||||
*
|
||||
* @param \PHP_CodeSniffer\Files\File $phpcs_file The file being scanned.
|
||||
* @param int $stack_ptr The position of the double quoted
|
||||
* string.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processVariableInString( File $phpcs_file, $stack_ptr ) {
|
||||
|
||||
$tokens = $phpcs_file->getTokens();
|
||||
|
||||
if ( preg_match_all( '|[^\\\]\${?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)|', $tokens[ $stack_ptr ]['content'], $matches ) > 0 ) {
|
||||
|
||||
// Merge any custom variables with the defaults.
|
||||
$this->mergeWhiteList();
|
||||
|
||||
foreach ( $matches[1] as $var_name ) {
|
||||
// If it's a php reserved var, then its ok.
|
||||
if ( isset( $this->phpReservedVars[ $var_name ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Likewise if it is a mixed-case var used by WordPress core.
|
||||
if ( isset( $this->wordpress_mixed_case_vars[ $var_name ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( false === self::isSnakeCase( $var_name ) ) {
|
||||
$error = 'Variable "$%s" is not in valid snake_case format, try "$%s"';
|
||||
$data = array(
|
||||
$var_name,
|
||||
Sniff::get_snake_case_name_suggestion( $var_name ),
|
||||
);
|
||||
$phpcs_file->addError( $error, $stack_ptr, 'InterpolatedVariableNotSnakeCase', $data );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the variable is in snake_case.
|
||||
*
|
||||
* @param string $var_name Variable name.
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSnakeCase( $var_name ) {
|
||||
return (bool) preg_match( '/^[a-z0-9_]+$/', $var_name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge a custom whitelist provided via a custom ruleset with the predefined whitelist,
|
||||
* if we haven't already.
|
||||
*
|
||||
* @since 0.10.0
|
||||
* @since 2.0.0 Removed unused $phpcs_file parameter.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function mergeWhiteList() {
|
||||
if ( $this->customPropertiesWhitelist !== $this->addedCustomProperties['properties'] ) {
|
||||
// Fix property potentially passed as comma-delimited string.
|
||||
$customProperties = Sniff::merge_custom_array( $this->customPropertiesWhitelist, array(), false );
|
||||
|
||||
$this->whitelisted_mixed_case_member_var_names = Sniff::merge_custom_array(
|
||||
$customProperties,
|
||||
$this->whitelisted_mixed_case_member_var_names
|
||||
);
|
||||
|
||||
$this->addedCustomProperties['properties'] = $this->customPropertiesWhitelist;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user