diff --git a/.config/.php-cs-fixer.dist.php b/.config/.php-cs-fixer.dist.php new file mode 100644 index 00000000..84c13f43 --- /dev/null +++ b/.config/.php-cs-fixer.dist.php @@ -0,0 +1,33 @@ +files() + ->in([ + __DIR__ . '/../src/', + __DIR__ . '/../tests/', + ]) + ->exclude([ + 'build', + 'Views', + ]) +; + +$overrides = [ + 'yoda_style' => ['identical' => false], +]; + +$options = [ + 'finder' => $finder, + 'cacheFile' => '../build/.php-cs-fixer.cache', +]; + +return (new PhpCsFixer\Config()) + ->setRules([ + '@PSR12' => true, + 'array_syntax' => ['syntax' => 'short'], + ]) + ->setCacheFile(__DIR__.'/../build/.php-cs-fixer.cache') + ->setFinder($finder) +; diff --git a/.config/rector.php b/.config/rector.php new file mode 100644 index 00000000..d2a7566d --- /dev/null +++ b/.config/rector.php @@ -0,0 +1,233 @@ +sets([ + LevelSetList::UP_TO_PHP_81, + PHPUnitSetList::PHPUNIT_100, + ]); + + // Run faster + $rectorConfig->parallel(); + + // The paths to refactor (can also be supplied with CLI arguments) + $rectorConfig->paths([ + __DIR__ . '/../src/', + // __DIR__ . '/tests/', + ]); + + // Include Composer's autoload - required for global execution, remove if running locally + $rectorConfig->autoloadPaths([ + __DIR__ . '/../vendor/autoload.php', + ]); + + // Do you need to include constants, class aliases, or a custom autoloader? + $rectorConfig->bootstrapFiles([ + realpath(getcwd()) . '/vendor/codeigniter4/framework/system/Test/bootstrap.php', + ]); + + // Set the target version for refactoring + $rectorConfig->phpVersion(PhpVersion::PHP_74); + + // Auto-import fully qualified class names + $rectorConfig->importNames(); + + // Are there files or rules you need to skip? + $rectorConfig->skip([ + __DIR__ . '/../app/Views', + ]); + + // auto import fully qualified class names + $rectorConfig->importNames(); + + // Early Return + $rectorConfig->rule(ChangeIfElseValueAssignToEarlyReturnRector::class); + $rectorConfig->rule(ChangeNestedForeachIfsToEarlyContinueRector::class); + $rectorConfig->rule(ChangeNestedIfsToEarlyReturnRector::class); + $rectorConfig->rule(PreparedValueToEarlyReturnRector::class); + $rectorConfig->rule(RemoveAlwaysElseRector::class); + $rectorConfig->rule(ReturnEarlyIfVariableRector::class); + // InstanceOf + $rectorConfig->rule(FlipNegatedTernaryInstanceofRector::class); + // Code Quality + $rectorConfig->rule(AbsolutizeRequireAndIncludePathRector::class); + $rectorConfig->rule(AndAssignsToSeparateLinesRector::class); + $rectorConfig->rule(ArrayKeyExistsTernaryThenValueToCoalescingRector::class); + $rectorConfig->rule(ArrayMergeOfNonArraysToSimpleArrayRector::class); + $rectorConfig->rule(BooleanNotIdenticalToNotIdenticalRector::class); + $rectorConfig->rule(BoolvalToTypeCastRector::class); + $rectorConfig->rule(CallableThisArrayToAnonymousFunctionRector::class); + $rectorConfig->rule(ChangeArrayPushToArrayAssignRector::class); + $rectorConfig->rule(CleanupUnneededNullsafeOperatorRector::class); + $rectorConfig->rule(CombineIfRector::class); + $rectorConfig->rule(CombinedAssignRector::class); + $rectorConfig->rule(CommonNotEqualRector::class); + $rectorConfig->rule(CompactToVariablesRector::class); + $rectorConfig->rule(CompleteDynamicPropertiesRector::class); + $rectorConfig->rule(CompleteMissingIfElseBracketRector::class); + $rectorConfig->rule(ConsecutiveNullCompareReturnsToNullCoalesceQueueRector::class); + $rectorConfig->rule(ConvertStaticPrivateConstantToSelfRector::class); + $rectorConfig->rule(FloatvalToTypeCastRector::class); + $rectorConfig->rule(ForRepeatedCountToOwnVariableRector::class); + $rectorConfig->rule(ForeachToInArrayRector::class); + $rectorConfig->rule(GetClassToInstanceOfRector::class); + $rectorConfig->rule(InlineIfToExplicitIfRector::class); + $rectorConfig->rule(InlineIsAInstanceOfRector::class); + $rectorConfig->rule(IntvalToTypeCastRector::class); + $rectorConfig->rule(JoinStringConcatRector::class); + $rectorConfig->rule(NewStaticToNewSelfRector::class); + $rectorConfig->rule(NumberCompareToMaxFuncCallRector::class); + $rectorConfig->rule(RemoveUselessIsObjectCheckRector::class); + $rectorConfig->rule(ReplaceMultipleBooleanNotRector::class); + $rectorConfig->rule(SetTypeToCastRector::class); + $rectorConfig->rule(ShortenElseIfRector::class); + $rectorConfig->rule(SimplifyArraySearchRector::class); + $rectorConfig->rule(SimplifyBoolIdenticalTrueRector::class); + $rectorConfig->rule(SimplifyConditionsRector::class); + $rectorConfig->rule(SimplifyDeMorganBinaryRector::class); + $rectorConfig->rule(SimplifyEmptyArrayCheckRector::class); + $rectorConfig->rule(SimplifyEmptyCheckOnEmptyArrayRector::class); + $rectorConfig->rule(SimplifyForeachToCoalescingRector::class); + $rectorConfig->rule(SimplifyFuncGetArgsCountRector::class); + $rectorConfig->rule(SimplifyIfElseToTernaryRector::class); + $rectorConfig->rule(SimplifyIfNotNullReturnRector::class); + $rectorConfig->rule(SimplifyIfNullableReturnRector::class); + $rectorConfig->rule(SimplifyIfReturnBoolRector::class); + $rectorConfig->rule(SimplifyInArrayValuesRector::class); + $rectorConfig->rule(SimplifyStrposLowerRector::class); + $rectorConfig->rule(SingleInArrayToCompareRector::class); + $rectorConfig->rule(SingularSwitchToIfRector::class); + $rectorConfig->rule(StrlenZeroToIdenticalEmptyStringRector::class); + $rectorConfig->rule(StrvalToTypeCastRector::class); + $rectorConfig->rule(SwitchNegatedTernaryRector::class); + $rectorConfig->rule(SwitchTrueToIfRector::class); + $rectorConfig->rule(TernaryEmptyArrayArrayDimFetchToCoalesceRector::class); + $rectorConfig->rule(TernaryFalseExpressionToIfRector::class); + $rectorConfig->rule(ThrowWithPreviousExceptionRector::class); + $rectorConfig->rule(UnnecessaryTernaryExpressionRector::class); + $rectorConfig->rule(UnwrapSprintfOneArgumentRector::class); + // Coding Style + $rectorConfig->rule(ArraySpreadInsteadOfArrayMergeRector::class); + $rectorConfig->rule(CallUserFuncArrayToVariadicRector::class); + $rectorConfig->rule(CallUserFuncToMethodCallRector::class); + $rectorConfig->rule(ConsistentImplodeRector::class); + $rectorConfig->rule(CountArrayToEmptyArrayComparisonRector::class); + $rectorConfig->rule(FuncGetArgsToVariadicParamRector::class); + $rectorConfig->rule(MakeInheritedMethodVisibilitySameAsParentRector::class); + $rectorConfig->rule(NewlineBeforeNewAssignSetRector::class); + $rectorConfig->rule(NullableCompareToNullRector::class); + $rectorConfig->rule(RemoveFinalFromConstRector::class); + $rectorConfig->rule(RemoveUselessAliasInUseStatementRector::class); + $rectorConfig->rule(SeparateMultiUseImportsRector::class); + $rectorConfig->rule(SplitDoubleAssignRector::class); + $rectorConfig->rule(SplitGroupedClassConstantsRector::class); + $rectorConfig->rule(SplitGroupedPropertiesRector::class); + $rectorConfig->rule(StaticArrowFunctionRector::class); + $rectorConfig->rule(StaticClosureRector::class); + $rectorConfig->rule(SymplifyQuoteEscapeRector::class); + $rectorConfig->rule(TernaryConditionVariableAssignmentRector::class); + $rectorConfig->rule(UseIncrementAssignRector::class); + $rectorConfig->rule(VersionCompareFuncCallToConstantRector::class); + $rectorConfig->rule(WrapEncapsedVariableInCurlyBracesRector::class); + // Removing + $rectorConfig->rule(ArgumentRemoverRector::class); + // Renaming + $rectorConfig->rule(RenameAnnotationRector::class); + $rectorConfig->rule(RenameConstantRector::class); +}; diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml deleted file mode 100644 index d3deab6d..00000000 --- a/.github/workflows/analyze.yml +++ /dev/null @@ -1,78 +0,0 @@ -# When a PR is opened or a push is made, perform -# a static analysis check on the code using PHPStan. -name: PHPStan - -on: - pull_request: - branches: - - 'develop' - paths: - - '**.php' - - 'composer.*' - - 'phpstan*' - - '.github/workflows/analyze.yml' - push: - branches: - - 'develop' - paths: - - '**.php' - - 'composer.*' - - 'phpstan*' - - '.github/workflows/analyze.yml' - -jobs: - build: - name: PHP ${{ matrix.php-versions }} Static Analysis - runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, '[ci skip]')" - strategy: - fail-fast: false - matrix: - php-versions: ['7.4', '8.0', '8.1', '8.2'] - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-versions }} - tools: phpstan, phpunit - extensions: intl, json, mbstring, xml - coverage: none - env: - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Get composer cache directory - run: echo "COMPOSER_CACHE_FILES_DIR=$(composer config cache-files-dir)" >> $GITHUB_ENV - - - name: Cache composer dependencies - uses: actions/cache@v3 - with: - path: ${{ env.COMPOSER_CACHE_FILES_DIR }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- - - - name: Create PHPStan cache directory - run: mkdir -p build/phpstan - - - name: Cache PHPStan results - uses: actions/cache@v3 - with: - path: build/phpstan - key: ${{ runner.os }}-phpstan-${{ github.sha }} - restore-keys: ${{ runner.os }}-phpstan- - - - name: Install dependencies (limited) - if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name }} - run: composer install --no-progress --no-interaction --prefer-dist --optimize-autoloader - - - name: Install dependencies (authenticated) - if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }} - run: composer install --no-progress --no-interaction --prefer-dist --optimize-autoloader - env: - COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }} - - - name: Run static analysis - run: vendor/bin/phpstan analyze diff --git a/.github/workflows/phpcsfixer.yml b/.github/workflows/phpcsfixer.yml new file mode 100644 index 00000000..4059a3eb --- /dev/null +++ b/.github/workflows/phpcsfixer.yml @@ -0,0 +1,55 @@ +name: PHPCSFixer + +on: + pull_request: + branches: + - develop + paths: + - "**.php" + - ".github/workflows/phpcsfixer.yml" + push: + branches: + - develop + paths: + - "**.php" + - ".github/workflows/phpcsfixer.yml" + +jobs: + build: + name: Coding Standards + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, '[ci skip]')" + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "8.1" + extensions: json, tokenizer + coverage: none + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Get composer cache directory + run: echo "COMPOSER_CACHE_FILES_DIR=$(composer config cache-files-dir)" >> $GITHUB_ENV + + - name: Cache composer dependencies + uses: actions/cache@v3 + with: + path: ${{ env.COMPOSER_CACHE_FILES_DIR }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: | + if [ -f composer.lock ]; then + composer install --no-progress --no-interaction --prefer-dist --optimize-autoloader + else + composer update --no-progress --no-interaction --prefer-dist --optimize-autoloader + fi + + - name: Check code for standards compliance + run: vendor/bin/php-cs-fixer fix --verbose --ansi --dry-run --using-cache=no --diff diff --git a/.gitignore b/.gitignore index 65860d88..4ca01338 100644 --- a/.gitignore +++ b/.gitignore @@ -110,3 +110,8 @@ nb-configuration.xml # Javascript assets #------------------------- node_modules/* + +#------------------------- +# MKDocs +#------------------------- +/site/ diff --git a/composer.json b/composer.json index e9a3b701..6e3adb41 100644 --- a/composer.json +++ b/composer.json @@ -24,9 +24,12 @@ "mikey179/vfsstream": "^1.6", "nexusphp/cs-config": "^3.1", "nexusphp/tachycardia": "^1.0", - "phpstan/phpstan": "^1.1", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.3", "phpunit/phpunit": "^9.1", "psr/container": "^1.0", + "rector/rector": "^1.0", + "roave/security-advisories": "dev-latest", "qossmic/deptrac-shim": "^0.24 || ^1.0.2" }, "suggest": { @@ -49,18 +52,18 @@ "minimum-stability": "dev", "prefer-stable": true, "scripts": { - "analyze": "phpstan analyze", - "ci": [ - "Composer\\Config::disableProcessTimeout", - "@deduplicate", - "@analyze", - "@test", - "@inspect", - "@style" + "clean": [ + "@lint", + "@style-fix", + "@rector-fix" ], "deduplicate": "phpcpd src/", "inspect": "deptrac analyze --cache-file=build/deptrac.cache", - "style": "php-cs-fixer fix --verbose --ansi --using-cache=no", + "lint": "vendor/bin/parallel-lint --exclude .git --exclude vendor .", + "rector": "rector process --config .config/rector.php --dry-run", + "rector-fix": "rector process --config .config/rector.php", + "style": "php-cs-fixer fix --config=.config/.php-cs-fixer.dist.php --dry-run", + "style-fix": "php-cs-fixer --config=.config/.php-cs-fixer.dist.php fix", "test": "./vendor/bin/phpunit" }, "support": { diff --git a/phpstan.neon.dist b/phpstan.neon.dist deleted file mode 100644 index 809d8cf6..00000000 --- a/phpstan.neon.dist +++ /dev/null @@ -1,26 +0,0 @@ -parameters: - tmpDir: build/phpstan - level: 4 - paths: - - src/ - - tests/ - bootstrapFiles: - - vendor/codeigniter4/framework/system/Test/bootstrap.php - excludePaths: - - src/Config/Routes.php - - src/Views/* - - src/*/Views/* - ignoreErrors: - universalObjectCratesClasses: - - CodeIgniter\Entity - - CodeIgniter\Entity\Entity - - Faker\Generator - scanDirectories: - - vendor/codeigniter4/framework/system/Helpers - - vendor/codeigniter4/settings/src/Helpers - - vendor/codeigniter4/shield/src/Helpers - - vendor/tatter/alerts/src/Helpers - dynamicConstantNames: - - APP_NAMESPACE - - CI_DEBUG - - ENVIRONMENT