Линтеры
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -7,8 +7,10 @@
|
||||
*.log
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
playlists.ini
|
||||
channels.json
|
||||
!.env.example
|
||||
.phpunit.result.cache
|
||||
.php-cs-fixer.cache
|
||||
|
||||
!/**/.gitkeep
|
||||
|
||||
732
.php-cs-fixer.php
Normal file
732
.php-cs-fixer.php
Normal file
@@ -0,0 +1,732 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) 2025, Антон Аксенов
|
||||
* This file is part of m3u.su project
|
||||
* MIT License: https://git.axenov.dev/IPTV/web/src/branch/master/LICENSE
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PhpCsFixer\Config;
|
||||
use PhpCsFixer\Finder;
|
||||
|
||||
// директории для проверки
|
||||
$includePaths = [
|
||||
'app/',
|
||||
'config/',
|
||||
];
|
||||
|
||||
// файлы для проверки
|
||||
$includeNames = [
|
||||
'public/index.php',
|
||||
];
|
||||
|
||||
// директории, исключённые из проверки
|
||||
$excludePaths = [
|
||||
'cache/',
|
||||
'views/',
|
||||
'vendor/',
|
||||
];
|
||||
|
||||
// файлы, исключённые из проверки
|
||||
$excludeNames = [
|
||||
];
|
||||
|
||||
// правила
|
||||
// https://cs.symfony.com/doc/rules/index.html
|
||||
// https://mlocati.github.io/php-cs-fixer-configurator/#version:3.83
|
||||
$rules = [
|
||||
// Alias
|
||||
'array_push' => true,
|
||||
'backtick_to_shell_exec' => true,
|
||||
'ereg_to_preg' => true,
|
||||
'mb_str_functions' => false,
|
||||
'modernize_strpos' => true,
|
||||
'no_alias_functions' => ['sets' => ['@all']],
|
||||
'no_alias_language_construct_call' => true,
|
||||
'no_mixed_echo_print' => ['use' => 'echo'],
|
||||
'pow_to_exponentiation' => true,
|
||||
'random_api_migration' => true,
|
||||
'set_type_to_cast' => false,
|
||||
|
||||
// Array Notation
|
||||
'array_syntax' => ['syntax' => 'short'],
|
||||
'no_multiline_whitespace_around_double_arrow' => true,
|
||||
'no_whitespace_before_comma_in_array' => ['after_heredoc' => false],
|
||||
'normalize_index_brace' => true,
|
||||
'return_to_yield_from' => false,
|
||||
'trim_array_spaces' => true,
|
||||
'whitespace_after_comma_in_array' => ['ensure_single_space' => true],
|
||||
'yield_from_array_to_yields' => false,
|
||||
|
||||
// Attribute Notation
|
||||
'attribute_empty_parentheses' => false,
|
||||
'ordered_attributes' => ['order' => [], 'sort_algorithm' => 'alpha'],
|
||||
|
||||
// Basic
|
||||
'braces_position' => [
|
||||
'allow_single_line_anonymous_functions' => false,
|
||||
'allow_single_line_empty_anonymous_classes' => false,
|
||||
'anonymous_classes_opening_brace' => 'next_line_unless_newline_at_signature_end',
|
||||
'anonymous_functions_opening_brace' => 'same_line',
|
||||
'classes_opening_brace' => 'next_line_unless_newline_at_signature_end',
|
||||
'control_structures_opening_brace' => 'same_line',
|
||||
'functions_opening_brace' => 'next_line_unless_newline_at_signature_end',
|
||||
],
|
||||
'encoding' => true,
|
||||
'no_multiple_statements_per_line' => true,
|
||||
'no_trailing_comma_in_singleline' => [
|
||||
'elements' => [
|
||||
'arguments',
|
||||
'array',
|
||||
'array_destructuring',
|
||||
'group_import',
|
||||
],
|
||||
],
|
||||
'non_printable_character' => ['use_escape_sequences_in_strings' => true],
|
||||
'numeric_literal_separator' => ['override_existing' => false, 'strategy' => 'no_separator'],
|
||||
'octal_notation' => true,
|
||||
'psr_autoloading' => ['dir' => null],
|
||||
|
||||
// Casing
|
||||
'class_reference_name_casing' => true,
|
||||
'constant_case' => ['case' => 'lower'],
|
||||
'integer_literal_case' => true,
|
||||
'lowercase_keywords' => true,
|
||||
'lowercase_static_reference' => true,
|
||||
'magic_constant_casing' => true,
|
||||
'magic_method_casing' => true,
|
||||
'native_function_casing' => true,
|
||||
'native_type_declaration_casing' => true,
|
||||
|
||||
// Cast Notation
|
||||
'cast_spaces' => ['space' => 'single'],
|
||||
'lowercase_cast' => true,
|
||||
'modernize_types_casting' => true,
|
||||
'no_short_bool_cast' => true,
|
||||
'no_unset_cast' => true,
|
||||
'short_scalar_cast' => true,
|
||||
|
||||
// Class Notation
|
||||
'class_attributes_separation' => [
|
||||
'elements' => [
|
||||
'const' => 'one',
|
||||
'method' => 'one',
|
||||
'property' => 'one',
|
||||
'trait_import' => 'none',
|
||||
'case' => 'one',
|
||||
],
|
||||
],
|
||||
'class_definition' => [
|
||||
'inline_constructor_arguments' => true,
|
||||
'multi_line_extends_each_single_line' => true,
|
||||
'single_item_single_line' => true,
|
||||
'single_line' => false,
|
||||
'space_before_parenthesis' => false,
|
||||
],
|
||||
'final_class' => false,
|
||||
'final_internal_class' => [
|
||||
'consider_absent_docblock_as_internal_class' => false,
|
||||
'exclude' => [],
|
||||
'include' => ['@IamTotallySureThisClassMustBeFinal'],
|
||||
],
|
||||
'final_public_method_for_abstract_class' => false,
|
||||
'no_blank_lines_after_class_opening' => true,
|
||||
'no_null_property_initialization' => false,
|
||||
'no_php4_constructor' => true,
|
||||
'no_unneeded_final_method' => ['private_methods' => true],
|
||||
'ordered_class_elements' => [
|
||||
'case_sensitive' => false,
|
||||
'order' => [
|
||||
'use_trait',
|
||||
'case',
|
||||
'constant_public',
|
||||
'constant_protected',
|
||||
'constant_private',
|
||||
'property_public',
|
||||
'property_protected',
|
||||
'property_private',
|
||||
'construct',
|
||||
'destruct',
|
||||
'method_public',
|
||||
'method_protected',
|
||||
'method_private',
|
||||
'magic',
|
||||
'phpunit',
|
||||
],
|
||||
'sort_algorithm' => 'none',
|
||||
],
|
||||
'ordered_interfaces' => [
|
||||
'case_sensitive' => false,
|
||||
'direction' => 'ascend',
|
||||
'order' => 'alpha',
|
||||
],
|
||||
'ordered_traits' => [
|
||||
'case_sensitive' => false,
|
||||
],
|
||||
'ordered_types' => [
|
||||
'case_sensitive' => false,
|
||||
'null_adjustment' => 'always_last',
|
||||
'sort_algorithm' => 'alpha',
|
||||
],
|
||||
'phpdoc_readonly_class_comment_to_keyword' => true,
|
||||
'protected_to_private' => false,
|
||||
'self_accessor' => true,
|
||||
'self_static_accessor' => true,
|
||||
'single_class_element_per_statement' => ['elements' => ['const', 'property']],
|
||||
'single_trait_insert_per_statement' => false,
|
||||
'modifier_keywords' => ['elements' => ['const', 'method', 'property']],
|
||||
|
||||
// Class Usage
|
||||
'date_time_immutable' => false, // при true ломает строку 'DateTime', что пока весьма важно
|
||||
|
||||
// Comment
|
||||
'comment_to_phpdoc' => ['ignored_tags' => []],
|
||||
// 'header_comment' => ['header' => ''],
|
||||
'multiline_comment_opening_closing' => false,
|
||||
'no_empty_comment' => true,
|
||||
'no_trailing_whitespace_in_comment' => true,
|
||||
'single_line_comment_spacing' => true,
|
||||
'single_line_comment_style' => ['comment_types' => ['asterisk', 'hash']],
|
||||
|
||||
// Constant Notation
|
||||
'native_constant_invocation' => [
|
||||
'exclude' => [],
|
||||
'include' => [],
|
||||
'fix_built_in' => false,
|
||||
'scope' => 'all',
|
||||
'strict' => false,
|
||||
],
|
||||
|
||||
// Control Structure
|
||||
'single_line_empty_body' => false, // иначе ругается на пустые классы
|
||||
'control_structure_braces' => true,
|
||||
'control_structure_continuation_position' => ['position' => 'same_line'],
|
||||
'elseif' => true,
|
||||
'empty_loop_body' => ['style' => 'braces'],
|
||||
'empty_loop_condition' => ['style' => 'while'],
|
||||
'include' => true,
|
||||
'no_alternative_syntax' => ['fix_non_monolithic_code' => true],
|
||||
'no_break_comment' => ['comment_text' => 'намеренно не останавливаем выполнение'],
|
||||
'no_superfluous_elseif' => true,
|
||||
'no_unneeded_braces' => ['namespaces' => false],
|
||||
'no_unneeded_control_parentheses' => [
|
||||
'statements' => ['break', 'clone', 'continue', 'echo_print', 'return', 'switch_case', 'yield', 'yield_from'],
|
||||
],
|
||||
'no_useless_else' => true,
|
||||
'simplified_if_return' => true,
|
||||
'switch_case_semicolon_to_colon' => true,
|
||||
'switch_case_space' => true,
|
||||
'switch_continue_to_break' => true,
|
||||
'trailing_comma_in_multiline' => true,
|
||||
'yoda_style' => [
|
||||
'equal' => false,
|
||||
'identical' => false,
|
||||
'less_and_greater' => false,
|
||||
],
|
||||
|
||||
// Doctrine Annotation
|
||||
// (не используем)
|
||||
|
||||
// Function Notation
|
||||
'combine_nested_dirname' => true,
|
||||
'date_time_create_from_format_call' => true,
|
||||
'fopen_flag_order' => false,
|
||||
// TODO 'fopen_flags' => ['b_mode' => false],
|
||||
'function_declaration' => [
|
||||
'closure_fn_spacing' => 'one',
|
||||
'closure_function_spacing' => 'one',
|
||||
'trailing_comma_single_line' => false,
|
||||
],
|
||||
'implode_call' => true,
|
||||
'lambda_not_used_import' => true,
|
||||
'method_argument_space' => [
|
||||
'after_heredoc' => true,
|
||||
'attribute_placement' => 'standalone',
|
||||
// TODO 'keep_multiple_spaces_after_comma' => true,
|
||||
'on_multiline' => 'ensure_fully_multiline',
|
||||
],
|
||||
'native_function_invocation' => [
|
||||
'exclude' => ['@all'],
|
||||
'include' => [],
|
||||
'scope' => 'all',
|
||||
'strict' => false,
|
||||
],
|
||||
'no_spaces_after_function_name' => true,
|
||||
'no_unreachable_default_argument_value' => true,
|
||||
'no_useless_sprintf' => true,
|
||||
// 'phpdoc_to_param_type' => [ // risky, experimenal :(
|
||||
// 'scalar_types' => true,
|
||||
// 'union_types' => true,
|
||||
// ],
|
||||
// 'phpdoc_to_property_type' => [ // risky, experimenal :(
|
||||
// 'scalar_types' => true,
|
||||
// 'union_types' => true,
|
||||
// ],
|
||||
// 'phpdoc_to_return_type' => [ // risky, experimenal :(
|
||||
// 'scalar_types' => true,
|
||||
// 'union_types' => true,
|
||||
// ],
|
||||
'regular_callable_call' => true,
|
||||
'return_type_declaration' => ['space_before' => 'none'],
|
||||
'single_line_throw' => false,
|
||||
'static_lambda' => true,
|
||||
'use_arrow_functions' => true,
|
||||
'void_return' => true,
|
||||
'nullable_type_declaration_for_default_null_value' => true,
|
||||
|
||||
// Import
|
||||
'fully_qualified_strict_types' => [
|
||||
'import_symbols' => true,
|
||||
'leading_backslash_in_global_namespace' => false,
|
||||
'phpdoc_tags' => [
|
||||
'param',
|
||||
'property',
|
||||
'property-read',
|
||||
'property-write',
|
||||
'phpstan-param',
|
||||
'phpstan-property',
|
||||
'phpstan-property-read',
|
||||
'phpstan-property-write',
|
||||
'phpstan-return',
|
||||
'phpstan-var',
|
||||
'psalm-param',
|
||||
'psalm-property',
|
||||
'psalm-property-read',
|
||||
'psalm-property-write',
|
||||
'psalm-return',
|
||||
'psalm-var',
|
||||
'return',
|
||||
'see',
|
||||
'link',
|
||||
'throws',
|
||||
'var',
|
||||
],
|
||||
],
|
||||
'global_namespace_import' => [
|
||||
'import_classes' => true,
|
||||
'import_constants' => false,
|
||||
'import_functions' => true,
|
||||
],
|
||||
'group_import' => false,
|
||||
'no_leading_import_slash' => true,
|
||||
'no_unneeded_import_alias' => true,
|
||||
'no_unused_imports' => true,
|
||||
'ordered_imports' => [
|
||||
'case_sensitive' => false,
|
||||
'imports_order' => ['class', 'const', 'function'],
|
||||
'sort_algorithm' => 'alpha',
|
||||
],
|
||||
'single_import_per_statement' => ['group_to_single_imports' => true],
|
||||
'single_line_after_imports' => true,
|
||||
|
||||
// Language Construct
|
||||
'class_keyword' => false, // при true ломает строку 'DateTime', что пока весьма важно
|
||||
'combine_consecutive_issets' => true,
|
||||
'combine_consecutive_unsets' => false, // иначе местами приводит к превышению длины строки
|
||||
'declare_equal_normalize' => ['space' => 'none'],
|
||||
'declare_parentheses' => true,
|
||||
'dir_constant' => true,
|
||||
'error_suppression' => false,
|
||||
'explicit_indirect_variable' => true,
|
||||
'function_to_constant' => [
|
||||
'functions' => [
|
||||
'get_called_class',
|
||||
'get_class',
|
||||
'get_class_this',
|
||||
'php_sapi_name',
|
||||
'phpversion',
|
||||
'pi',
|
||||
],
|
||||
],
|
||||
'get_class_to_class_keyword' => true,
|
||||
'is_null' => false,
|
||||
'no_unset_on_property' => false,
|
||||
'nullable_type_declaration' => ['syntax' => 'question_mark'],
|
||||
'single_space_around_construct' => [
|
||||
'constructs_contain_a_single_space' => ['yield_from'],
|
||||
'constructs_followed_by_a_single_space' => [
|
||||
'abstract',
|
||||
'as',
|
||||
'attribute',
|
||||
// 'break',
|
||||
'case',
|
||||
'catch',
|
||||
'class',
|
||||
'clone',
|
||||
'comment',
|
||||
'const',
|
||||
'const_import',
|
||||
'continue',
|
||||
'do',
|
||||
'echo',
|
||||
'else',
|
||||
'elseif',
|
||||
'enum',
|
||||
'extends',
|
||||
'final',
|
||||
'finally',
|
||||
'for',
|
||||
'foreach',
|
||||
'function',
|
||||
'function_import',
|
||||
'global',
|
||||
'goto',
|
||||
'if',
|
||||
'implements',
|
||||
'include',
|
||||
'include_once',
|
||||
'instanceof',
|
||||
'insteadof',
|
||||
'interface',
|
||||
'match',
|
||||
'named_argument',
|
||||
'namespace',
|
||||
'new',
|
||||
'open_tag_with_echo',
|
||||
'php_doc',
|
||||
'php_open',
|
||||
'print',
|
||||
'private',
|
||||
'protected',
|
||||
'public',
|
||||
'readonly',
|
||||
'require',
|
||||
'require_once',
|
||||
'return',
|
||||
'static',
|
||||
'switch',
|
||||
'throw',
|
||||
'trait',
|
||||
'try',
|
||||
'type_colon',
|
||||
'use',
|
||||
'use_lambda',
|
||||
'use_trait',
|
||||
'var',
|
||||
'while',
|
||||
'yield',
|
||||
'yield_from',
|
||||
],
|
||||
'constructs_preceded_by_a_single_space' => ['as', 'else', 'elseif', 'use_lambda'],
|
||||
],
|
||||
|
||||
// List Notation
|
||||
'list_syntax' => ['syntax' => 'short'],
|
||||
|
||||
// Namespace Notation
|
||||
'blank_line_after_namespace' => true,
|
||||
'blank_lines_before_namespace' => ['max_line_breaks' => 2, 'min_line_breaks' => 2],
|
||||
'clean_namespace' => true,
|
||||
'no_leading_namespace_whitespace' => true,
|
||||
|
||||
// Naming
|
||||
'no_homoglyph_names' => true,
|
||||
|
||||
// Operator
|
||||
'assign_null_coalescing_to_coalesce_equal' => true,
|
||||
'binary_operator_spaces' => [
|
||||
'default' => 'single_space',
|
||||
'operators' => [],
|
||||
],
|
||||
'concat_space' => ['spacing' => 'one'],
|
||||
'increment_style' => ['style' => 'pre'],
|
||||
'logical_operators' => true,
|
||||
'long_to_shorthand_operator' => true,
|
||||
'new_with_parentheses' => ['anonymous_class' => true, 'named_class' => true],
|
||||
'no_space_around_double_colon' => true,
|
||||
'no_useless_concat_operator' => ['juggle_simple_strings' => false],
|
||||
'no_useless_nullsafe_operator' => true,
|
||||
'not_operator_with_space' => false,
|
||||
'not_operator_with_successor_space' => false,
|
||||
'object_operator_without_whitespace' => true,
|
||||
'operator_linebreak' => [
|
||||
'only_booleans' => true,
|
||||
'position' => 'beginning',
|
||||
],
|
||||
'standardize_increment' => true,
|
||||
'standardize_not_equals' => true,
|
||||
'ternary_operator_spaces' => true,
|
||||
'ternary_to_elvis_operator' => false,
|
||||
'ternary_to_null_coalescing' => true,
|
||||
'unary_operator_spaces' => ['only_dec_inc' => false],
|
||||
|
||||
// PHP Tag
|
||||
'blank_line_after_opening_tag' => true,
|
||||
'echo_tag_syntax' => [
|
||||
'format' => 'short',
|
||||
'long_function' => 'echo',
|
||||
'shorten_simple_statements_only' => true,
|
||||
],
|
||||
'full_opening_tag' => true,
|
||||
'linebreak_after_opening_tag' => true,
|
||||
'no_closing_tag' => true,
|
||||
|
||||
// PHPUnit
|
||||
'php_unit_assert_new_names' => true,
|
||||
'php_unit_attributes' => ['keep_annotations' => false],
|
||||
'php_unit_construct' => ['assertions' => ['assertEquals', 'assertSame', 'assertNotEquals', 'assertNotSame']],
|
||||
'php_unit_data_provider_name' => ['prefix' => 'provide', 'suffix' => ''],
|
||||
'php_unit_data_provider_return_type' => false,
|
||||
'php_unit_data_provider_static' => ['force' => true],
|
||||
'php_unit_dedicate_assert' => ['target' => 'newest'],
|
||||
'php_unit_dedicate_assert_internal_type' => ['target' => 'newest'],
|
||||
'php_unit_expectation' => ['target' => 'newest'],
|
||||
'php_unit_fqcn_annotation' => true,
|
||||
'php_unit_internal_class' => false,
|
||||
'php_unit_method_casing' => ['case' => 'camel_case'],
|
||||
'php_unit_mock' => ['target' => 'newest'],
|
||||
'php_unit_mock_short_will_return' => true,
|
||||
'php_unit_namespaced' => ['target' => 'newest'],
|
||||
'php_unit_no_expectation_annotation' => ['target' => 'newest', 'use_class_const' => true],
|
||||
'php_unit_set_up_tear_down_visibility' => true,
|
||||
'php_unit_size_class' => false,
|
||||
'php_unit_strict' => [
|
||||
'assertions' => [
|
||||
'assertAttributeEquals',
|
||||
'assertAttributeNotEquals',
|
||||
// 'assertEquals', // не всегда возможно
|
||||
// 'assertNotEquals', // не всегда возможно
|
||||
],
|
||||
],
|
||||
'php_unit_test_annotation' => ['style' => 'prefix'],
|
||||
'php_unit_test_case_static_method_calls' => ['call_type' => 'this', 'methods' => []],
|
||||
'php_unit_test_class_requires_covers' => false,
|
||||
|
||||
// PHPDoc
|
||||
'align_multiline_comment' => ['comment_type' => 'phpdocs_only'],
|
||||
'general_phpdoc_annotation_remove' => [
|
||||
'annotations' => ['author', 'package', 'subpackage'],
|
||||
'case_sensitive' => false,
|
||||
],
|
||||
'general_phpdoc_tag_rename' => [
|
||||
'case_sensitive' => false,
|
||||
'fix_annotation' => true,
|
||||
'fix_inline' => true,
|
||||
'replacements' => [
|
||||
'inheritDocs' => 'inheritDoc',
|
||||
// 'link' => 'see', // phpdoc_no_alias_tag
|
||||
],
|
||||
],
|
||||
'no_blank_lines_after_phpdoc' => true,
|
||||
'no_empty_phpdoc' => true,
|
||||
'no_superfluous_phpdoc_tags' => false,
|
||||
'phpdoc_add_missing_param_annotation' => ['only_untyped' => true],
|
||||
'phpdoc_align' => [
|
||||
'align' => 'left',
|
||||
'spacing' => 1,
|
||||
'tags' => [
|
||||
'param',
|
||||
'property',
|
||||
'property-read',
|
||||
'property-write',
|
||||
'phpstan-param',
|
||||
'phpstan-property',
|
||||
'phpstan-property-read',
|
||||
'phpstan-property-write',
|
||||
'phpstan-return',
|
||||
'phpstan-var',
|
||||
'psalm-param',
|
||||
'psalm-property',
|
||||
'psalm-property-read',
|
||||
'psalm-property-write',
|
||||
'psalm-return',
|
||||
'psalm-var',
|
||||
'return',
|
||||
'see',
|
||||
'link',
|
||||
'throws',
|
||||
'var',
|
||||
],
|
||||
],
|
||||
'phpdoc_annotation_without_dot' => true,
|
||||
'phpdoc_array_type' => false,
|
||||
'phpdoc_indent' => true,
|
||||
'phpdoc_inline_tag_normalizer' => [
|
||||
'tags' => ['example', 'id', 'internal', 'inheritdoc', 'inheritdocs', 'link', 'source', 'see', 'tutorial'],
|
||||
],
|
||||
'phpdoc_line_span' => [
|
||||
'const' => 'multi',
|
||||
'method' => 'multi',
|
||||
'property' => 'multi',
|
||||
],
|
||||
'phpdoc_list_type' => false,
|
||||
'phpdoc_no_access' => true,
|
||||
'phpdoc_no_alias_tag' => [
|
||||
'replacements' => [
|
||||
'property-read' => 'property',
|
||||
'property-write' => 'property',
|
||||
'type' => 'var',
|
||||
'link' => 'see',
|
||||
],
|
||||
],
|
||||
'phpdoc_no_empty_return' => false,
|
||||
'phpdoc_no_package' => false, // general_phpdoc_annotation_remove
|
||||
'phpdoc_no_useless_inheritdoc' => true,
|
||||
'phpdoc_order_by_value' => ['annotations' => []],
|
||||
'phpdoc_order' => ['order' => ['param', 'return', 'throws', 'covers', 'dataProvider']],
|
||||
'phpdoc_param_order' => true,
|
||||
'phpdoc_return_self_reference' => [
|
||||
'replacements' => [
|
||||
'this' => '$this',
|
||||
'@this' => '$this',
|
||||
'$self' => 'self',
|
||||
'@self' => 'self',
|
||||
'$static' => 'static',
|
||||
'@static' => 'static',
|
||||
],
|
||||
],
|
||||
'phpdoc_scalar' => ['types' => ['boolean', 'callback', 'double', 'integer', 'real', 'str']],
|
||||
'phpdoc_separation' => ['groups' => [], 'skip_unlisted_annotations' => true],
|
||||
'phpdoc_single_line_var_spacing' => true,
|
||||
'phpdoc_summary' => false,
|
||||
'phpdoc_tag_casing' => [
|
||||
'tags' => [
|
||||
'param',
|
||||
'property',
|
||||
'property-read',
|
||||
'property-write',
|
||||
'phpstan-param',
|
||||
'phpstan-property',
|
||||
'phpstan-property-read',
|
||||
'phpstan-property-write',
|
||||
'phpstan-return',
|
||||
'phpstan-var',
|
||||
'psalm-param',
|
||||
'psalm-property',
|
||||
'psalm-property-read',
|
||||
'psalm-property-write',
|
||||
'psalm-return',
|
||||
'psalm-var',
|
||||
'return',
|
||||
'see',
|
||||
'link',
|
||||
'throws',
|
||||
'var',
|
||||
],
|
||||
],
|
||||
'phpdoc_tag_type' => [
|
||||
'tags' => [
|
||||
'api' => 'annotation',
|
||||
'author' => 'annotation',
|
||||
'copyright' => 'annotation',
|
||||
'deprecated' => 'annotation',
|
||||
'example' => 'annotation',
|
||||
'global' => 'annotation',
|
||||
'inheritDoc' => 'annotation',
|
||||
'internal' => 'annotation',
|
||||
'license' => 'annotation',
|
||||
'method' => 'annotation',
|
||||
'package' => 'annotation',
|
||||
'param' => 'annotation',
|
||||
'property' => 'annotation',
|
||||
'return' => 'annotation',
|
||||
'see' => 'annotation',
|
||||
'since' => 'annotation',
|
||||
'throws' => 'annotation',
|
||||
'todo' => 'annotation',
|
||||
'uses' => 'annotation',
|
||||
'var' => 'annotation',
|
||||
'version' => 'annotation',
|
||||
],
|
||||
],
|
||||
'phpdoc_to_comment' => false, // при true ломаются докблоки к выражениям, которые обязаны быть докблоками, а не многострочными комментами
|
||||
'phpdoc_trim_consecutive_blank_line_separation' => true,
|
||||
'phpdoc_trim' => true,
|
||||
'phpdoc_types' => ['groups' => ['simple', 'alias', 'meta']],
|
||||
'phpdoc_types_order' => [
|
||||
'case_sensitive' => false,
|
||||
'null_adjustment' => 'always_last',
|
||||
'sort_algorithm' => 'none',
|
||||
],
|
||||
'phpdoc_var_annotation_correct_order' => true,
|
||||
'phpdoc_var_without_name' => true,
|
||||
|
||||
// Return Notation
|
||||
'no_useless_return' => true,
|
||||
'return_assignment' => true,
|
||||
'simplified_null_return' => true,
|
||||
|
||||
// Semicolon
|
||||
'multiline_whitespace_before_semicolons' => ['strategy' => 'no_multi_line'],
|
||||
'no_empty_statement' => true,
|
||||
'no_singleline_whitespace_before_semicolons' => true,
|
||||
'semicolon_after_instruction' => true,
|
||||
'space_after_semicolon' => ['remove_in_empty_for_expressions' => true],
|
||||
|
||||
// Strict
|
||||
'declare_strict_types' => true,
|
||||
'strict_comparison' => true,
|
||||
'strict_param' => false,
|
||||
|
||||
// String Notation
|
||||
'explicit_string_variable' => true,
|
||||
'heredoc_closing_marker' => [
|
||||
'closing_marker' => 'EOD',
|
||||
'explicit_heredoc_style' => false,
|
||||
'reserved_closing_markers' => ['SQL', 'EOF'],
|
||||
],
|
||||
'heredoc_to_nowdoc' => false,
|
||||
'multiline_string_to_heredoc' => false,
|
||||
'no_binary_string' => true,
|
||||
'no_trailing_whitespace_in_string' => false,
|
||||
'simple_to_complex_string_variable' => true,
|
||||
'single_quote' => ['strings_containing_single_quote_chars' => false],
|
||||
'string_implicit_backslashes' => [
|
||||
'double_quoted' => 'escape',
|
||||
'heredoc' => 'escape',
|
||||
'single_quoted' => 'unescape',
|
||||
],
|
||||
'string_length_to_empty' => false,
|
||||
'string_line_ending' => true,
|
||||
|
||||
// Whitespace
|
||||
'array_indentation' => true,
|
||||
'blank_line_before_statement' => ['statements' => ['declare', 'return', 'throw', 'try']],
|
||||
'blank_line_between_import_groups' => true,
|
||||
'compact_nullable_type_declaration' => true,
|
||||
'heredoc_indentation' => ['indentation' => 'start_plus_one'],
|
||||
'indentation_type' => true,
|
||||
'line_ending' => true,
|
||||
'method_chaining_indentation' => true,
|
||||
'no_extra_blank_lines' => [
|
||||
'tokens' => [
|
||||
'attribute',
|
||||
'break',
|
||||
'case',
|
||||
'continue',
|
||||
'curly_brace_block',
|
||||
'default',
|
||||
'extra',
|
||||
'parenthesis_brace_block',
|
||||
'return',
|
||||
'square_brace_block',
|
||||
'switch',
|
||||
'throw',
|
||||
'use',
|
||||
],
|
||||
],
|
||||
'no_spaces_around_offset' => ['positions' => ['inside', 'outside']],
|
||||
'no_trailing_whitespace' => true,
|
||||
'no_whitespace_in_blank_line' => true,
|
||||
'single_blank_line_at_eof' => true,
|
||||
'spaces_inside_parentheses' => ['space' => 'none'],
|
||||
'statement_indentation' => ['stick_comment_to_next_continuous_control_statement' => false],
|
||||
'type_declaration_spaces' => ['elements' => ['function', 'property']],
|
||||
'types_spaces' => ['space' => 'none', 'space_multiple_catch' => null],
|
||||
];
|
||||
|
||||
$finder = (new Finder())
|
||||
->ignoreVCSIgnored(true) // игнорируем игнорируемое
|
||||
->in($includePaths) // добавляем директории
|
||||
->append($includeNames) // добавляем файлы
|
||||
->exclude($excludePaths) // исключаем директории
|
||||
->notPath($excludeNames); // исключаем файлы
|
||||
|
||||
return (new Config())
|
||||
// спорная фигня, пока не
|
||||
// ->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect());
|
||||
->setFinder($finder)
|
||||
->setRules($rules) // ставим правила
|
||||
->setRiskyAllowed(true); // рискованные правила разрешаем, но в общий список добавляем аккуратно
|
||||
@@ -26,6 +26,16 @@
|
||||
"telegram-bot/api": "^2.5",
|
||||
"vlucas/phpdotenv": "^5.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.24.1",
|
||||
"friendsofphp/php-cs-fixer": "^3.86.0",
|
||||
"jetbrains/phpstorm-attributes": "^1.2",
|
||||
"mockery/mockery": "^1.6.12",
|
||||
"phpstan/phpstan": "^1.12.28",
|
||||
"phpstan/phpstan-mockery": "^1.1.3",
|
||||
"phpunit/phpunit": "^10.5.53",
|
||||
"squizlabs/php_codesniffer": "^3.13.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "app/"
|
||||
|
||||
4492
composer.lock
generated
4492
composer.lock
generated
File diff suppressed because it is too large
Load Diff
425
linter
Executable file
425
linter
Executable file
@@ -0,0 +1,425 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2025, Антон Аксенов
|
||||
# This file is part of m3u.su project
|
||||
# MIT License: https://git.axenov.dev/IPTV/web/src/branch/master/LICENSE
|
||||
#
|
||||
|
||||
# shellcheck disable=SC2015
|
||||
|
||||
# set -x
|
||||
# set -o pipefail
|
||||
|
||||
########################################################
|
||||
# Служебные исходные переменные
|
||||
########################################################
|
||||
|
||||
# имя контейнера
|
||||
CONTAINER="m3u-su-web"
|
||||
|
||||
# команда для запуска
|
||||
COMMAND="$1"; shift
|
||||
|
||||
# имена всех новых, скопированных, изменённых и перемещённых php-файлов относительно корня репозитория
|
||||
FILES=($(git diff --name-only --diff-filter=ACMR HEAD 2>/dev/null | grep -e '.php$'))
|
||||
|
||||
# признак запуска гитом (хук)
|
||||
IS_FROM_GIT="$(env | grep -c "GIT_EDITOR=:")"
|
||||
|
||||
# признак запуска изнутри контейнера
|
||||
[[ -f /.dockerenv ]] && IS_FROM_CONTAINER=1 || IS_FROM_CONTAINER=0
|
||||
|
||||
# признак режима отладки
|
||||
[[ $LINTER_DEBUG == 1 ]] && DEBUG_MODE=1
|
||||
[[ $LINTER_DEBUG -gt 1 ]] && set -x
|
||||
|
||||
########################################################
|
||||
# Ввод/вывод
|
||||
########################################################
|
||||
|
||||
which tput > /dev/null 2>&1 && [ "$(tput -T"$TERM" colors)" -gt 8 ] && CAN_USE_COLORS=1 || CAN_USE_COLORS=0
|
||||
LINTER_COLORS=${LINTER_COLORS:-$CAN_USE_COLORS}
|
||||
[[ "$LINTER_COLORS" == 1 ]] && FRESET="$(tput sgr0)" || FRESET=''
|
||||
[[ "$LINTER_COLORS" == 1 ]] && FBOLD="$(tput bold)" || FBOLD=''
|
||||
[[ "$LINTER_COLORS" == 1 ]] && FDIM="$(tput dim)" || FDIM=''
|
||||
[[ "$LINTER_COLORS" == 1 ]] && FBLACK="$(tput setaf 0)" || FBLACK=''
|
||||
[[ "$LINTER_COLORS" == 1 ]] && FRED="$(tput setaf 1)" || FRED=''
|
||||
[[ "$LINTER_COLORS" == 1 ]] && FWHITE="$(tput setaf 7)" || FWHITE=''
|
||||
[[ "$LINTER_COLORS" == 1 ]] && FGREEN="$(tput setaf 2)" || FGREEN=''
|
||||
[[ "$LINTER_COLORS" == 1 ]] && FBRED="$(tput setab 1)" || FBRED=''
|
||||
[[ "$LINTER_COLORS" == 1 ]] && FBYELLOW="$(tput setab 3)" || FBYELLOW=''
|
||||
[[ "$LINTER_COLORS" == 1 ]] && FBLYELLOW="$(tput setab 11)" || FBLYELLOW=''
|
||||
|
||||
print() {
|
||||
echo -e "$*${FRESET}"
|
||||
}
|
||||
|
||||
debug() {
|
||||
[[ "$LINTER_DEBUG" != 1 ]] && return
|
||||
|
||||
if [ "$2" ]; then
|
||||
print "${FDIM}${FBOLD}${FRESET}${FDIM} ${FUNCNAME[1]:-?}():${BASH_LINENO:-?}\t$1 " >&2
|
||||
else
|
||||
print "${FDIM}${FBOLD}${FRESET}${FDIM} $*" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
var_dump() {
|
||||
debug "$1 = ${!1}"
|
||||
}
|
||||
|
||||
title() {
|
||||
print "${FBOLD}${FWHITE}$*${FRESET}"
|
||||
}
|
||||
|
||||
success() {
|
||||
print "${FBOLD}${FGREEN}$*${FRESET}"
|
||||
}
|
||||
|
||||
warn() {
|
||||
print "${FBOLD}${FBYELLOW}${FRED} Внимание! ${FRESET} $*${FRESET}"
|
||||
}
|
||||
|
||||
error() {
|
||||
print "${FBOLD}${FBRED}${FWHITE} Ошибка: ${FRESET}${FBOLD}${FRED} $*${FRESET}" >&2
|
||||
}
|
||||
|
||||
########################################################
|
||||
# Базовые хелперы
|
||||
########################################################
|
||||
|
||||
# Проверяет существование функции с именем $1
|
||||
is_function() {
|
||||
declare -F "$1" > /dev/null
|
||||
}
|
||||
|
||||
# Выполняет команду в контейнере
|
||||
docker.exec() {
|
||||
if [[ "$IS_FROM_GIT" == 1 ]]; then
|
||||
cmd="docker exec -i $CONTAINER $*"
|
||||
else
|
||||
cmd="docker exec -it $CONTAINER $*"
|
||||
fi
|
||||
debug "Команда: $cmd"
|
||||
$cmd
|
||||
}
|
||||
|
||||
########################################################
|
||||
# Хелперы для обработки команд
|
||||
########################################################
|
||||
|
||||
# Выводит некоторую отладочную информацию
|
||||
status() {
|
||||
[[ "$LINTER_DEBUG" == 0 ]] && return
|
||||
debug "* Внутри контейнера: ${IS_FROM_CONTAINER}"
|
||||
debug "* Через git: ${IS_FROM_GIT}"
|
||||
debug "* Изменённых файлов: ${#FILES[@]}"
|
||||
}
|
||||
|
||||
# Запускает phpcs в контейнере
|
||||
exec_phpcsniffer_pre() {
|
||||
docker.exec vendor/bin/phpcs -p "$@"
|
||||
}
|
||||
|
||||
# Запускает phpcbf в контейнере
|
||||
exec_phpcsniffer_fix() {
|
||||
docker.exec vendor/bin/phpcbf "$@"
|
||||
}
|
||||
|
||||
# Запускает php-cs-fixer в контейнере
|
||||
exec_phpcsfixer_pre() {
|
||||
docker.exec vendor/bin/php-cs-fixer fix -vv --config=./.php-cs-fixer.php --using-cache=no --format=@auto --diff --dry-run "$@"
|
||||
}
|
||||
|
||||
# Запускает php-cs-fixer в контейнере
|
||||
exec_phpcsfixer_fix() {
|
||||
docker.exec vendor/bin/php-cs-fixer fix -vv --config=./.php-cs-fixer.php --using-cache=no --format=@auto "$@"
|
||||
}
|
||||
|
||||
# Запускает phpstan в контейнере
|
||||
exec_phpstan() {
|
||||
docker.exec vendor/bin/phpstan -v --memory-limit=1G analyse "$@"
|
||||
}
|
||||
|
||||
# Запускает phpunit в контейнере
|
||||
exec_phpunit() {
|
||||
docker.exec vendor/bin/phpunit "$@"
|
||||
}
|
||||
|
||||
########################################################
|
||||
# Главные функции обработки команд
|
||||
########################################################
|
||||
|
||||
# Устанавливает pre-commit git хук
|
||||
install() {
|
||||
status
|
||||
[[ -d ./.git/hooks ]] || {
|
||||
print "Не найден репозиторий '$(pwd)', пропускаю"
|
||||
exit
|
||||
}
|
||||
cp -f "$0" ./.git/hooks/pre-commit && \
|
||||
success "Pre-commit hook установлен" || \
|
||||
error "Pre-commit хук НЕ установлен"
|
||||
}
|
||||
|
||||
# Запускает проверку код-стайла по всему проекту или только изменённым файлам
|
||||
style() {
|
||||
title "[php-cs-fixer] Запущена проверка код-стайла"
|
||||
status
|
||||
if [[ $# -gt 0 ]]; then
|
||||
exec_phpcsfixer_pre "$@" || {
|
||||
error "[php-cs-fixer] Проверка код-стайла завершена с ошибками!"
|
||||
exit 1
|
||||
}
|
||||
else
|
||||
exec_phpcsfixer_pre "${FILES[@]}" || {
|
||||
error "[php-cs-fixer] Проверка код-стайла завершена с ошибками!"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
success "[php-cs-fixer] Проверка код-стайла завершена успешно!"
|
||||
}
|
||||
|
||||
# Запускает исправление код-стайла по всему проекту или только изменённым файлам
|
||||
fix() {
|
||||
title "[php-cs-fixer] Запущено исправление код-стайла"
|
||||
status
|
||||
if [[ $# -gt 0 ]]; then
|
||||
exec_phpcsfixer_fix "$@" || {
|
||||
error "[php-cs-fixer] Исправление код-стайла завершено с ошибками!"
|
||||
exit 2
|
||||
}
|
||||
else
|
||||
exec_phpcsfixer_fix "${FILES[@]}" || {
|
||||
error "[php-cs-fixer] Исправление код-стайла завершено с ошибками!"
|
||||
exit 2
|
||||
}
|
||||
fi
|
||||
success "[php-cs-fixer] Исправление код-стайла завершено успешно!"
|
||||
}
|
||||
|
||||
phpcs() {
|
||||
title "[phpcs] Запущена проверка код-стайла"
|
||||
status
|
||||
if [[ $# -gt 0 ]]; then
|
||||
exec_phpcsniffer_pre "$@" || {
|
||||
error "[phpcs] Проверка код-стайла завершена с ошибками!"
|
||||
exit 3
|
||||
}
|
||||
else
|
||||
exec_phpcsniffer_pre "${FILES[@]}" || {
|
||||
error "[phpcs] Проверка код-стайла завершена с ошибками!"
|
||||
exit 3
|
||||
}
|
||||
fi
|
||||
success "[phpcs] Проверка код-стайла завершена успешно!"
|
||||
}
|
||||
|
||||
phpcbf() {
|
||||
title "[phpcs] Запущено исправление код-стайла"
|
||||
status
|
||||
if [[ $# -gt 0 ]]; then
|
||||
exec_phpcsniffer_fix "$@" || {
|
||||
error "[phpcs] Исправление код-стайла завершено с ошибками!"
|
||||
exit 4
|
||||
}
|
||||
else
|
||||
exec_phpcsniffer_fix "${FILES[@]}"|| {
|
||||
error "[phpcs] Исправление код-стайла завершено с ошибками!"
|
||||
exit 4
|
||||
}
|
||||
fi
|
||||
success "[phpcs] Исправление код-стайла завершено успешно!"
|
||||
}
|
||||
|
||||
# Запускает статический анализ по всему проекту или только изменённым файлам
|
||||
stan() {
|
||||
title "[phpstan] Запуск статического анализа"
|
||||
status
|
||||
if [[ $# -gt 0 ]]; then
|
||||
exec_phpstan "$@" || {
|
||||
error "[phpstan] Статический анализ завершён с ошибками!"
|
||||
exit 5
|
||||
}
|
||||
else
|
||||
exec_phpstan "${FILES[@]}" || {
|
||||
error "[phpstan] Статический анализ завершён с ошибками!"
|
||||
exit 5
|
||||
}
|
||||
fi
|
||||
success "[phpstan] Статический анализ завершён успешно!"
|
||||
}
|
||||
|
||||
# Запускает выполнение тестов
|
||||
tests() {
|
||||
title "[phpunit] Запуск тестирования"
|
||||
exec_phpunit "$@" || {
|
||||
error "[phpunit] Тестирование завершено с ошибками!"
|
||||
exit 6
|
||||
}
|
||||
success "[phpunit] Тестирование завершено успешно!"
|
||||
}
|
||||
|
||||
lint() {
|
||||
style
|
||||
phpcs
|
||||
stan
|
||||
}
|
||||
|
||||
########################################################
|
||||
# Команды справки
|
||||
########################################################
|
||||
|
||||
help() {
|
||||
print "${FBOLD}PHP-линтер"
|
||||
is_function "help.$1" && help."$1" && exit
|
||||
print "Использование:"
|
||||
print " ./linter КОМАНДА [АРГУМЕНТЫ]"
|
||||
print
|
||||
print "Доступные КОМАНДЫ:"
|
||||
print " h|help - вывести это сообщение"
|
||||
print " i|install - установить как pre-commit git хук"
|
||||
print " s|style - запустить проверку код-стайла (php-cs-fixer)"
|
||||
print " f|fix - запустить исправление код-стайла (php-cs-fixer)"
|
||||
print " p|phpcs - запустить проверку код-стайла (phpcs)"
|
||||
print " c|phpcbf - запустить исправление код-стайла (phpcbf)"
|
||||
print " a|stan - запустить статический анализ (phpstan)"
|
||||
print " l|lint - запустить style + phpcs + stan"
|
||||
print " t|tests - протестировать (phpunit)"
|
||||
print
|
||||
print "КОМАНДЫ 's', 'f', 'p', 'c' и 'a' могут принимать собственные АРГУМЕНТЫ php-cs-fixer, phpcs, phpcbf и phpstan соответственно."
|
||||
print
|
||||
print "Переменные окружения:"
|
||||
print " LINTER_COLORS - принудительно включить (1) или выключить (0, по умолчанию) форматированный вывод"
|
||||
print " LINTER_DEBUG - включить простую отладку (1), построчную (2) или выключить (0, по умолчанию)"
|
||||
}
|
||||
|
||||
help.help() {
|
||||
print "КОМАНДА: help"
|
||||
print "Отображает справку по скрипту и его командам."
|
||||
print
|
||||
print "Использование:"
|
||||
print " ./linter help [КОМАНДА]"
|
||||
print
|
||||
print "Если КОМАНДА не указана, будет отображена справка по скрипту со списком допустимых КОМАНД."
|
||||
}
|
||||
|
||||
help.install() {
|
||||
print "КОМАНДА: install"
|
||||
print "Устанавливает linter в качестве pre-commit git-хука."
|
||||
print
|
||||
print "Использование:"
|
||||
print " ./linter install"
|
||||
print
|
||||
print "Если в директории проекта нет репозитория, то установка будет пропущена без ошибки."
|
||||
print "Перед коммитом будут выполнены команды lint и tests."
|
||||
}
|
||||
|
||||
help.style() {
|
||||
print "КОМАНДА: style"
|
||||
print "Запускает php-cs-fixer для проверки код-стайла."
|
||||
print "Поддерживает передачу собственных аргументов."
|
||||
print
|
||||
print "Использование:"
|
||||
print " ./linter style [АРГУМЕНТЫ]"
|
||||
print
|
||||
print "Допустимые АРГУМЕНТЫ: https://cs.symfony.com/doc/usage.html"
|
||||
print "Если АРГУМЕНТЫ не указаны, будут анализированы только изменённые и новые php-файлы."
|
||||
print "Если рабочее дерево git чистое, то инструмент отработает согласно своего конфига."
|
||||
}
|
||||
|
||||
help.fix() {
|
||||
print "КОМАНДА: fix"
|
||||
print "Запускает php-cs-fixer для исправления код-стайла."
|
||||
print "Поддерживает передачу собственных аргументов."
|
||||
print
|
||||
print "Использование:"
|
||||
print " ./linter fix [АРГУМЕНТЫ]"
|
||||
print
|
||||
print "Допустимые АРГУМЕНТЫ: https://cs.symfony.com/doc/usage.html"
|
||||
print "Если АРГУМЕНТЫ не указаны, будут анализированы только изменённые и новые php-файлы."
|
||||
print "Если рабочее дерево git чистое, то инструмент отработает согласно своего конфига."
|
||||
}
|
||||
|
||||
help.phpcs() {
|
||||
print "КОМАНДА: phpcs"
|
||||
print "Запускает phpcs для проверки код-стайла."
|
||||
print "Поддерживает передачу собственных аргументов."
|
||||
print
|
||||
print "Использование:"
|
||||
print " ./linter phpcs [АРГУМЕНТЫ]"
|
||||
print
|
||||
print "Допустимые АРГУМЕНТЫ: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Usage"
|
||||
print "Если АРГУМЕНТЫ не указаны, будут анализированы только изменённые и новые php-файлы."
|
||||
print "Если рабочее дерево git чистое, то инструмент отработает согласно своего конфига."
|
||||
}
|
||||
|
||||
help.phpcbf() {
|
||||
print "КОМАНДА: phpcbf"
|
||||
print "Запускает phpcbf для исправления код-стайла."
|
||||
print "Поддерживает передачу собственных аргументов."
|
||||
print
|
||||
print "Использование:"
|
||||
print " ./linter phpcbf [АРГУМЕНТЫ]"
|
||||
print
|
||||
print "Допустимые АРГУМЕНТЫ: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Fixing-Errors-Automatically#using-the-php-code-beautifier-and-fixer"
|
||||
print "Если АРГУМЕНТЫ не указаны, будут анализированы только изменённые и новые php-файлы."
|
||||
print "Если рабочее дерево git чистое, то инструмент отработает согласно своего конфига."
|
||||
}
|
||||
|
||||
help.stan() {
|
||||
print "КОМАНДА: stan"
|
||||
print "Запускает phpstan для статического анализа."
|
||||
print
|
||||
print "Использование:"
|
||||
print " ./linter stan [АРГУМЕНТЫ]"
|
||||
print
|
||||
print "Допустимые АРГУМЕНТЫ: https://phpstan.org/user-guide/command-line-usage"
|
||||
print "Если АРГУМЕНТЫ не указаны, будут анализированы только изменённые и новые php-файлы."
|
||||
print "Если рабочее дерево git чистое, то инструмент отработает согласно своего конфига."
|
||||
}
|
||||
|
||||
help.lint() {
|
||||
print "КОМАНДА: lint"
|
||||
print "Последовательно запускает команды 'style', 'phpcs' и 'stan'."
|
||||
print "Не поддерживает передачу аргументов."
|
||||
print
|
||||
print "Использование:"
|
||||
print " ./linter lint"
|
||||
print
|
||||
print "Для дополнительной информации см. './linter help' для соответствующей команды."
|
||||
}
|
||||
|
||||
help.tests() {
|
||||
print "КОМАНДА: tests"
|
||||
print "Последовательно запускает phpunit для статического анализа."
|
||||
print
|
||||
print "Использование:"
|
||||
print " ./linter tests [АРГУМЕНТЫ]"
|
||||
print
|
||||
print "Допустимые АРГУМЕНТЫ: https://docs.phpunit.de/en/10.5/textui.html#command-line-options"
|
||||
}
|
||||
|
||||
########################################################
|
||||
# Точка входа
|
||||
########################################################
|
||||
|
||||
if [[ "$IS_FROM_GIT" -gt 0 ]]; then
|
||||
status && lint && tests
|
||||
success "Коммит разрешён!"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case "$COMMAND" in
|
||||
h|help ) help "$1" ;;
|
||||
i|install ) install ;;
|
||||
s|style ) style "$@" ;;
|
||||
f|fix ) fix "$@" ;;
|
||||
p|phpcs ) phpcs "$@" ;;
|
||||
c|phpcbf ) phpcbf "$@" ;;
|
||||
a|stan ) stan "$@" ;;
|
||||
l|lint ) lint ;;
|
||||
t|tests ) tests "$@" ;;
|
||||
* ) warn "неизвестная команда, вызываю help"; help ;;
|
||||
esac
|
||||
|
||||
435
phpcs.xml
Normal file
435
phpcs.xml
Normal file
@@ -0,0 +1,435 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ Copyright (c) 2025, Антон Аксенов
|
||||
~ This file is part of m3u.su project
|
||||
~ MIT License: https://git.axenov.dev/IPTV/web/src/branch/master/LICENSE
|
||||
-->
|
||||
|
||||
<!--
|
||||
https://github.com/PHPCSStandards/PHP_CodeSniffer/tree/master/src/Standards
|
||||
https://github.com/PHPCSStandards/PHPCSExtra?tab=readme-ov-file#sniffs
|
||||
https://kalimah-apps.com/phpcs/docs/
|
||||
https://github.com/slevomat/coding-standard
|
||||
-->
|
||||
<ruleset name="m3u.su Coding Standards">
|
||||
<description>m3u.su Coding Standards</description>
|
||||
|
||||
<arg name="extensions" value="php"/>
|
||||
<!--<arg name="report" value="summary"/>-->
|
||||
<arg name="colors"/>
|
||||
<arg name="parallel" value="5"/>
|
||||
<arg name="tab-width" value="4"/>
|
||||
<arg value="p"/>
|
||||
<arg value="s"/>
|
||||
|
||||
<file>app/</file>
|
||||
<file>config/</file>
|
||||
<file>public/index.php</file>
|
||||
|
||||
<exclude-pattern>cache/</exclude-pattern>
|
||||
<exclude-pattern>views/</exclude-pattern>
|
||||
<exclude-pattern>vendor/</exclude-pattern>
|
||||
|
||||
<!-- ============================================================================================= -->
|
||||
|
||||
<!--<rule ref="Generic.Arrays.ArrayIndent">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="indent" value="4" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="Generic.Arrays.DisallowLongArraySyntax" />-->
|
||||
|
||||
<!--<rule ref="Generic.Classes.DuplicateClassName" />-->
|
||||
|
||||
<!--<rule ref="Generic.CodeAnalysis.AssignmentInCondition" />-->
|
||||
<!--<rule ref="Generic.CodeAnalysis.EmptyPHPStatement" />-->
|
||||
<!--<rule ref="Generic.CodeAnalysis.EmptyStatement" />-->
|
||||
<!--<rule ref="Generic.CodeAnalysis.ForLoopShouldBeWhileLoop" />-->
|
||||
<!--<rule ref="Generic.CodeAnalysis.JumbledIncrementer" />-->
|
||||
<!--<rule ref="Generic.CodeAnalysis.UnconditionalIfStatement" />-->
|
||||
<!--<rule ref="Generic.CodeAnalysis.UnnecessaryFinalModifier" />-->
|
||||
<!--<rule ref="Generic.CodeAnalysis.UnusedFunctionParameter" />-->
|
||||
<!--<rule ref="Generic.CodeAnalysis.UselessOverridingMethod" />-->
|
||||
|
||||
<rule ref="Generic.ControlStructures.DisallowYodaConditions" />
|
||||
<rule ref="Generic.ControlStructures.InlineControlStructure">
|
||||
<properties>
|
||||
<property name="error" value="false" />
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="Generic.Files.ByteOrderMark" />
|
||||
<rule ref="Generic.Files.EndFileNewline" />
|
||||
<!--<rule ref="Generic.Files.InlineHTML" />-->
|
||||
<!--<rule ref="Generic.Files.LineEndings">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="eolChar" value="\n" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<rule ref="Generic.Files.LineLength">
|
||||
<properties>
|
||||
<property name="lineLimit" value="120" />
|
||||
<property name="absoluteLineLimit" value="120" />
|
||||
<property name="ignoreComments" value="false" />
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="Generic.Files.OneClassPerFile" />
|
||||
<rule ref="Generic.Files.OneInterfacePerFile" />
|
||||
<rule ref="Generic.Files.OneObjectStructurePerFile" />
|
||||
<rule ref="Generic.Files.OneTraitPerFile" />
|
||||
|
||||
<!--<rule ref="Generic.Formatting.NoSpaceAfterCast" />-->
|
||||
|
||||
<!--<rule ref="Generic.Functions.FunctionCallArgumentSpacing" />-->
|
||||
<!--<rule ref="Generic.Functions.OpeningFunctionBraceBsdAllman">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="checkFunctions" value="false" />-->
|
||||
<!-- <property name="checkClosures" value="false" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
|
||||
<rule ref="Generic.Metrics.CyclomaticComplexity">
|
||||
<!-- https://ru.wikipedia.org/wiki/Цикломатическая_сложность -->
|
||||
<properties>
|
||||
<!-- TODO это высокие настройки, надо понижать -->
|
||||
<property name="complexity" value="7" />
|
||||
<property name="absoluteComplexity" value="10" />
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="Generic.Metrics.NestingLevel">
|
||||
<properties>
|
||||
<property name="nestingLevel" value="7" />
|
||||
<property name="absoluteNestingLevel" value="10" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!--<rule ref="Generic.NamingConventions.CamelCapsFunctionName">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="strict" value="true" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<rule ref="Generic.NamingConventions.ConstructorName" />
|
||||
<rule ref="Generic.NamingConventions.UpperCaseConstantName" />
|
||||
|
||||
<rule ref="Generic.PHP.BacktickOperator" />
|
||||
<rule ref="Generic.PHP.CharacterBeforePHPOpeningTag" />
|
||||
<rule ref="Generic.PHP.DeprecatedFunctions" />
|
||||
<rule ref="Generic.PHP.DisallowAlternativePHPTags" />
|
||||
<rule ref="Generic.PHP.DisallowRequestSuperglobal" />
|
||||
<rule ref="Generic.PHP.DisallowShortOpenTag" />
|
||||
<rule ref="Generic.PHP.DiscourageGoto" />
|
||||
<rule ref="Generic.PHP.ForbiddenFunctions">
|
||||
<properties>
|
||||
<property name="forbiddenFunctions" type="array">
|
||||
<element key="eval" value="null"/>
|
||||
<element key="sizeof" value="count"/>
|
||||
<element key="delete" value="unset"/>
|
||||
<element key="join" value="implode"/>
|
||||
<element key="create_function" value="null"/>
|
||||
<element key="var_dump" value="null"/>
|
||||
<element key="dd" value="null"/>
|
||||
<element key="dump" value="null"/>
|
||||
<element key="print" value="null"/>
|
||||
<!--<element key="echo" value="null"/>-->
|
||||
<!--<element key="print_r" value="null"/>-->
|
||||
<!--<element key="var_export" value="null"/>-->
|
||||
</property>
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="Generic.PHP.RequireStrictTypes" />
|
||||
<rule ref="Generic.PHP.SAPIUsage" />
|
||||
<rule ref="Generic.PHP.Syntax" />
|
||||
|
||||
<rule ref="Generic.VersionControl.GitMergeConflict" />
|
||||
|
||||
<!--<rule ref="Generic.WhiteSpace.ArbitraryParenthesesSpacing">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="ignoreNewlines" value="true" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<rule ref="Generic.WhiteSpace.DisallowTabIndent" />
|
||||
|
||||
<!-- ============================================================================================= -->
|
||||
|
||||
<!--<rule ref="PEAR.Classes.ClassDeclaration" />-->
|
||||
|
||||
<!--<rule ref="PEAR.Commenting.InlineComment" />-->
|
||||
|
||||
<!--<rule ref="PEAR.ControlStructures.ControlSignature">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="ignoreComments" value="true" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="PEAR.ControlStructures.MultiLineCondition">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="indent" value="4" />-->
|
||||
<!-- </properties>-->
|
||||
<!-- <!– первый операнд в мультистроковых ифах должен быть на новой строке –>-->
|
||||
<!-- <exclude name="PEAR.ControlStructures.MultiLineCondition.SpacingAfterOpenBrace" />-->
|
||||
<!-- <!– не каждый операнд в мультистроковых ифах должен начинаться с булева оператора –>-->
|
||||
<!-- <exclude name="PEAR.ControlStructures.MultiLineCondition.StartWithBoolean" />-->
|
||||
<!--</rule>-->
|
||||
|
||||
<!--<rule ref="PEAR.Functions.FunctionCallSignature">-->
|
||||
<!-- <!–конфликтует с PEAR.WhiteSpace.ObjectOperatorIndent–>-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="allowMultipleArguments" value="true" />-->
|
||||
<!-- <property name="indent" value="4" />-->
|
||||
<!-- <property name="requiredSpacesAfterOpen" value="0" />-->
|
||||
<!-- <property name="requiredSpacesBeforeClose" value="0" />-->
|
||||
<!-- </properties>-->
|
||||
<!-- <!– ругается на открывающие скобки в одной строке –>-->
|
||||
<!-- <exclude name="PEAR.Functions.FunctionCallSignature.ContentAfterOpenBracket" />-->
|
||||
<!-- <!– ругается на закрывающие скобки в одной строке –>-->
|
||||
<!-- <exclude name="PEAR.Functions.FunctionCallSignature.CloseBracketLine" />-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="PEAR.Functions.FunctionDeclaration">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="indent" value="4" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="PEAR.Functions.ValidDefaultValue" />-->
|
||||
|
||||
<!--<rule ref="PEAR.WhiteSpace.ObjectOperatorIndent">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="indent" value="4" />-->
|
||||
<!-- <property name="multilevel" value="true" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="PEAR.WhiteSpace.ScopeClosingBrace">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="indent" value="4" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="PEAR.WhiteSpace.ScopeIndent">-->
|
||||
<!-- <!– конфликтует с Generic.WhiteSpace.ScopeIndent –>-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="exact" value="false" />-->
|
||||
<!-- <property name="tabIndent" value="false" />-->
|
||||
<!-- <property name="ignoreIndentationTokens" type="array" value="T_COMMENT,T_DOC_COMMENT_OPEN_TAG,T_CASE" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
|
||||
<!-- ============================================================================================= -->
|
||||
|
||||
<!--<rule ref="PSR1.Classes.ClassDeclaration" />-->
|
||||
|
||||
<!--<rule ref="PSR1.Files.SideEffects" />-->
|
||||
|
||||
<!--<rule ref="PSR1.Methods.CamelCapsMethodName" />-->
|
||||
|
||||
<!-- ============================================================================================= -->
|
||||
|
||||
<!--<rule ref="PSR2.Classes.ClassDeclaration">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="indent" value="4" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="PSR2.Classes.PropertyDeclaration" />-->
|
||||
|
||||
<rule ref="PSR2.ControlStructures.ControlStructureSpacing">
|
||||
<!-- первый операнд в мультистроковых ифах должен быть на новой строке -->
|
||||
<exclude name="PSR2.ControlStructures.ControlStructureSpacing.SpacingAfterOpenBrace" />
|
||||
</rule>
|
||||
<!--<rule ref="PSR2.ControlStructures.ElseIfDeclaration" />-->
|
||||
<!--<rule ref="PSR2.ControlStructures.SwitchDeclaration">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="indent" value="4" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
|
||||
<!--<rule ref="PSR2.Files.ClosingTag" />-->
|
||||
<!--<rule ref="PSR2.Files.EndFileNewline" />-->
|
||||
|
||||
<!--<rule ref="PSR2.Methods.FunctionCallSignature">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="allowMultipleArguments" value="true" />-->
|
||||
<!-- <property name="indent" value="4" />-->
|
||||
<!-- <property name="requiredSpacesAfterOpen" value="0" />-->
|
||||
<!-- <property name="requiredSpacesBeforeClose" value="0" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="PSR2.Methods.FunctionClosingBrace" />-->
|
||||
<!--<rule ref="PSR2.Methods.MethodDeclaration" />-->
|
||||
|
||||
<!--<rule ref="PSR2.Namespaces.NamespaceDeclaration" />-->
|
||||
<!--<rule ref="PSR2.Namespaces.UseDeclaration" />-->
|
||||
|
||||
<!-- ============================================================================================= -->
|
||||
|
||||
<!--<rule ref="PSR12.Classes.AnonClassDeclaration">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="indent" value="4" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="PSR12.Classes.ClassInstantiation" />-->
|
||||
<!--<rule ref="PSR12.Classes.ClosingBrace" />-->
|
||||
<!--<rule ref="PSR12.Classes.OpeningBraceSpace" />-->
|
||||
|
||||
<!--<rule ref="PSR12.ControlStructures.BooleanOperatorPlacement">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="allowOnly" value="first" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="PSR12.ControlStructures.ControlStructureSpacing">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="indent" value="4" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
|
||||
<!--<rule ref="PSR12.Files.DeclareStatement" />-->
|
||||
<!--<rule ref="PSR12.Files.ImportStatement" />-->
|
||||
<!--<rule ref="PSR12.Files.OpenTag" />-->
|
||||
|
||||
<!--<rule ref="PSR12.Functions.NullableTypeDeclaration" />-->
|
||||
<!--<rule ref="PSR12.Functions.ReturnTypeDeclaration" />-->
|
||||
|
||||
<!--<rule ref="PSR12.Keywords.ShortFormTypeKeywords" />-->
|
||||
|
||||
<!--<rule ref="PSR12.Operators.OperatorSpacing" />-->
|
||||
|
||||
<!--<rule ref="PSR12.Properties.ConstantVisibility" />-->
|
||||
|
||||
<!--<rule ref="PSR12.Traits.UseDeclaration" />-->
|
||||
|
||||
<!-- ============================================================================================= -->
|
||||
|
||||
<!--<rule ref="Squiz.Arrays.ArrayBracketSpacing" />-->
|
||||
|
||||
<!--<rule ref="Squiz.Classes.ClassDeclaration">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="indent" value="4" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="Squiz.Classes.ClassFileName" />-->
|
||||
<!--<rule ref="Squiz.Classes.LowercaseClassKeywords" />-->
|
||||
<!--<rule ref="Squiz.Classes.SelfMemberReference" />-->
|
||||
<!--<rule ref="Squiz.Classes.ValidClassName" />-->
|
||||
|
||||
<!--<rule ref="Squiz.Commenting.DocCommentAlignment" />-->
|
||||
<!--<rule ref="Squiz.Commenting.EmptyCatchComment" />-->
|
||||
<!--<rule ref="Squiz.Commenting.FunctionCommentThrowTag">-->
|
||||
<!-- <!– не умеет считать выбросы исключений из глубины –>-->
|
||||
<!-- <exclude name="Squiz.Commenting.FunctionCommentThrowTag.WrongNumber" />-->
|
||||
<!--</rule>-->
|
||||
|
||||
<!--<rule ref="Squiz.Commenting.VariableComment">-->
|
||||
<!-- <!– требует длинное название типа (integer, boolean, ...) вместо нормального (int, bool, ..) –>-->
|
||||
<!-- <exclude name="Squiz.Commenting.VariableComment.IncorrectVarType" />-->
|
||||
<!-- <!– не понимает наличие аннотации между докблоком и декларацией –>-->
|
||||
<!-- <exclude name="Squiz.Commenting.VariableComment.WrongStyle" />-->
|
||||
<!-- <exclude name="Squiz.WhiteSpace.MemberVarSpacing.Incorrect" />-->
|
||||
<!--</rule>-->
|
||||
|
||||
<!--<rule ref="Squiz.ControlStructures.ControlSignature">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="requiredSpacesBeforeColon" value="0" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="Squiz.ControlStructures.ForEachLoopDeclaration" />-->
|
||||
<!--<rule ref="Squiz.ControlStructures.ForLoopDeclaration">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="ignoreNewlines" value="false" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="Squiz.ControlStructures.LowercaseDeclaration" />-->
|
||||
<!--<rule ref="Squiz.ControlStructures.SwitchDeclaration">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="indent" value="4" />-->
|
||||
<!-- </properties>-->
|
||||
<!-- <!– требует выход из кейса на 1 уровне с кейсом –>-->
|
||||
<!-- <exclude name="Squiz.ControlStructures.SwitchDeclaration.BreakIndent" />-->
|
||||
<!--</rule>-->
|
||||
|
||||
<!--<rule ref="Squiz.Functions.FunctionDeclaration">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="ignoreComments" value="false" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="equalsSpacing" value="1" />-->
|
||||
<!-- <property name="requiredSpacesAfterOpen" value="0" />-->
|
||||
<!-- <property name="requiredSpacesBeforeClose" value="0" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
|
||||
<!--<rule ref="Squiz.Functions.FunctionDuplicateArgument" />-->
|
||||
<!--<rule ref="Squiz.Functions.GlobalFunction" />-->
|
||||
<!--<rule ref="Squiz.Functions.LowercaseFunctionKeywords" />-->
|
||||
<!--<rule ref="Squiz.Functions.MultiLineFunctionDeclaration" />-->
|
||||
|
||||
<!--<rule ref="Squiz.NamingConventions.ValidFunctionName">-->
|
||||
<!-- <!– требует _ в начале приватных методов –>-->
|
||||
<!-- <exclude name="Squiz.NamingConventions.ValidFunctionName.PrivateNoUnderscore" />-->
|
||||
<!--</rule>-->
|
||||
|
||||
<!--<rule ref="Squiz.Objects.DisallowObjectStringIndex" />-->
|
||||
<!--<rule ref="Squiz.Objects.ObjectMemberComma" />-->
|
||||
|
||||
<!--<rule ref="Squiz.Operators.IncrementDecrementUsage" />-->
|
||||
<!--<rule ref="Squiz.Operators.ValidLogicalOperators" />-->
|
||||
|
||||
<!--TODO проблема с комментариями //, которые занимают полную строку -->
|
||||
<!-- <rule ref="Squiz.PHP.CommentedOutCode" /> -->
|
||||
<!--<rule ref="Squiz.PHP.DiscouragedFunctions">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="error" value="true" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="Squiz.PHP.Eval" />-->
|
||||
<!--<rule ref="Squiz.PHP.GlobalKeyword" />-->
|
||||
<!--<rule ref="Squiz.PHP.InnerFunctions" />-->
|
||||
<!--<rule ref="Squiz.PHP.LowercasePHPFunctions" />-->
|
||||
<!--<rule ref="Squiz.PHP.NonExecutableCode" />-->
|
||||
|
||||
<!--<rule ref="Squiz.Scope.MemberVarScope" />-->
|
||||
<!--<rule ref="Squiz.Scope.MethodScope" />-->
|
||||
<!--<rule ref="Squiz.Scope.StaticThisUsage" />-->
|
||||
|
||||
<!--<rule ref="Squiz.Strings.EchoedStrings" />-->
|
||||
|
||||
<!--<rule ref="Squiz.WhiteSpace.CastSpacing" />-->
|
||||
<!--<rule ref="Squiz.WhiteSpace.ControlStructureSpacing">-->
|
||||
<!-- <!– первый операнд в мультистроковых ифах должен быть на новой строке –>-->
|
||||
<!-- <exclude name="Squiz.WhiteSpace.ControlStructureSpacing.SpacingAfterOpenBrace" />-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="Squiz.WhiteSpace.FunctionOpeningBraceSpace" />-->
|
||||
<!--<rule ref="Squiz.WhiteSpace.FunctionSpacing">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="spacing" value="1" />-->
|
||||
<!-- <property name="spacingBeforeFirst" value="0" />-->
|
||||
<!-- <property name="spacingAfterLast" value="0" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="Squiz.WhiteSpace.LanguageConstructSpacing" />-->
|
||||
<!--<rule ref="Squiz.WhiteSpace.LogicalOperatorSpacing" />-->
|
||||
<!--<rule ref="Squiz.WhiteSpace.MemberVarSpacing">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="spacing" value="1" />-->
|
||||
<!-- <property name="spacingBeforeFirst" value="0" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="Squiz.WhiteSpace.ObjectOperatorSpacing">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="ignoreNewlines" value="true" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="Squiz.WhiteSpace.OperatorSpacing">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="ignoreNewlines" value="true" />-->
|
||||
<!-- <property name="ignoreSpacingBeforeAssignments" value="false" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
<!--<rule ref="Squiz.WhiteSpace.PropertyLabelSpacing" />-->
|
||||
<!--<rule ref="Squiz.WhiteSpace.ScopeClosingBrace" />-->
|
||||
<!--<rule ref="Squiz.WhiteSpace.ScopeKeywordSpacing" />-->
|
||||
<!--<rule ref="Squiz.WhiteSpace.SemicolonSpacing" />-->
|
||||
<!--<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace">-->
|
||||
<!-- <properties>-->
|
||||
<!-- <property name="ignoreBlankLines" value="false" />-->
|
||||
<!-- </properties>-->
|
||||
<!--</rule>-->
|
||||
|
||||
<!-- ============================================================================================= -->
|
||||
|
||||
</ruleset>
|
||||
48
phpstan.neon
Normal file
48
phpstan.neon
Normal file
@@ -0,0 +1,48 @@
|
||||
includes:
|
||||
- ./vendor/phpstan/phpstan-mockery/extension.neon
|
||||
|
||||
parameters:
|
||||
# https://phpstan.org/config-reference
|
||||
level: 8
|
||||
polluteScopeWithLoopInitialAssignments: true
|
||||
polluteScopeWithAlwaysIterableForeach: true
|
||||
# polluteScopeWithBlock: true # v2+
|
||||
checkExplicitMixedMissingReturn: true
|
||||
checkFunctionNameCase: true
|
||||
checkInternalClassCaseSensitivity: true
|
||||
reportMaybesInMethodSignatures: false # при true перегиб для объявленных в интерфейсах шаблонов
|
||||
reportMaybesInPropertyPhpDocTypes: false # при true перегиб для объявленных в интерфейсах шаблонов
|
||||
reportStaticMethodSignatures: true
|
||||
checkTooWideReturnTypesInProtectedAndPublicMethods: false
|
||||
checkUninitializedProperties: false
|
||||
checkDynamicProperties: false
|
||||
rememberPossiblyImpureFunctionValues: true
|
||||
# checkBenevolentUnionTypes: true # перегиб для union-types
|
||||
reportPossiblyNonexistentGeneralArrayOffset: false
|
||||
reportPossiblyNonexistentConstantArrayOffset: false
|
||||
reportAlwaysTrueInLastCondition: true
|
||||
reportWrongPhpDocTypeInVarTag: true
|
||||
reportAnyTypeWideningInVarTag: true
|
||||
checkMissingOverrideMethodAttribute: true
|
||||
treatPhpDocTypesAsCertain: false
|
||||
reportUnmatchedIgnoredErrors: false
|
||||
checkMissingCallableSignature: true
|
||||
parallel:
|
||||
jobSize: 5
|
||||
maximumNumberOfProcesses: 16
|
||||
minimumNumberOfJobsPerProcess: 1
|
||||
paths:
|
||||
- app/
|
||||
- config/
|
||||
- public/index.php
|
||||
excludePaths:
|
||||
- cache/
|
||||
- views/
|
||||
- vendor/
|
||||
ignoreErrors:
|
||||
# https://phpstan.org/user-guide/ignoring-errors
|
||||
# https://phpstan.org/error-identifiers
|
||||
|
||||
# требует явно расписывать все итерируемые типы, структуры полей и т.д.
|
||||
# можно раскомментировать для уточнения типов при разработке, но убирать пока рано
|
||||
# - identifier: missingType.iterableValue
|
||||
43
phpunit.xml
Normal file
43
phpunit.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2025, Антон Аксенов
|
||||
~ This file is part of m3u.su project
|
||||
~ MIT License: https://git.axenov.dev/IPTV/web/src/branch/master/LICENSE
|
||||
-->
|
||||
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
>
|
||||
<!--<testsuites>-->
|
||||
<!-- <testsuite name="Controllers">-->
|
||||
<!-- <directory>tests/Http/Controllers</directory>-->
|
||||
<!-- </testsuite>-->
|
||||
<!--</testsuites>-->
|
||||
|
||||
<source>
|
||||
<include>
|
||||
<directory>app/</directory>
|
||||
<directory>config/</directory>
|
||||
<directory>public/</directory>
|
||||
</include>
|
||||
<exclude>
|
||||
<directory>cache/</directory>
|
||||
<directory>views/</directory>
|
||||
<directory>vendor/</directory>
|
||||
</exclude>
|
||||
</source>
|
||||
|
||||
<php>
|
||||
<server name="APP_ENV" value="testing"/>
|
||||
<server name="BCRYPT_ROUNDS" value="4"/>
|
||||
<server name="CACHE_DRIVER" value="array"/>
|
||||
<server name="DB_CONNECTION" value="sqlite"/>
|
||||
<server name="DB_DATABASE" value=":memory:"/>
|
||||
<server name="MAIL_MAILER" value="array"/>
|
||||
<server name="QUEUE_CONNECTION" value="sync"/>
|
||||
<server name="SESSION_DRIVER" value="array"/>
|
||||
<server name="TELESCOPE_ENABLED" value="false"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
Reference in New Issue
Block a user