diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..651cc00 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,37 @@ +# EditorConfig - Preserves premium comment formatting +# https://editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 4 + +[*.php] +indent_style = space +indent_size = 4 +max_line_length = 120 + +# Preserves spaces in comments (no trim) +[*.php] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 + +[*.{json,json5}] +indent_size = 2 + +[*.{md,markdown}] +trim_trailing_whitespace = false +max_line_length = off + +[composer.json] +indent_size = 4 + +[{package.json,*.yml,*.yaml}] +indent_size = 2 diff --git a/.env b/.env new file mode 100644 index 0000000..3e85f1e --- /dev/null +++ b/.env @@ -0,0 +1,212 @@ +# ============================================================================== +# KaririCode DevKit - Environment Configuration +# ============================================================================== +# Professional environment variables for Docker Compose +# Copy to .env and customize: cp .env.example .env +# ============================================================================== + +# ============================================================================== +# APPLICATION +# ============================================================================== +APP_NAME=kariricode-devkit +APP_ENV=development +APP_DEBUG=true +APP_SECRET=change-me-in-production +APP_VERSION=dev +SYMFONY_ENV=dev + +# ============================================================================== +# DOCKER & SYSTEM +# ============================================================================== +# User/Group IDs (match host user for volume permissions) +# Note: PHP container runs as root internally but processes run as www-data +UID=1000 +GID=1000 + +# Timezone +TZ=UTC + +# Volume consistency (macOS performance) +VOLUME_CONSISTENCY=cached + +# ============================================================================== +# PORTS +# ============================================================================== +APP_PORT=8089 +REDIS_PORT=6379 +MEMCACHED_PORT=11211 + +# ============================================================================== +# PHP SERVICE (kariricode/php-api-stack) +# ============================================================================== +PHP_STACK_VERSION=dev + +# PHP Configuration +PHP_MEMORY_LIMIT=2G +PHP_MAX_EXECUTION_TIME=300 +PHP_UPLOAD_MAX_FILESIZE=50M +PHP_POST_MAX_SIZE=50M + +# Resource Limits +PHP_CPU_LIMIT=2.0 +PHP_CPU_RESERVATION=0.5 +PHP_MEMORY_RESERVATION=512M + +# OPcache +OPCACHE_ENABLE=1 +OPCACHE_VALIDATE_TIMESTAMPS=1 +OPCACHE_REVALIDATE_FREQ=2 + +# PHP-FPM Configuration +PHP_FPM_PM=dynamic +PHP_FPM_PM_MAX_CHILDREN=50 +PHP_FPM_PM_START_SERVERS=5 +PHP_FPM_PM_MIN_SPARE_SERVERS=5 +PHP_FPM_PM_MAX_SPARE_SERVERS=10 +PHP_FPM_PM_MAX_REQUESTS=500 + +# ============================================================================== +# XDEBUG +# ============================================================================== +XDEBUG_MODE=off +XDEBUG_CLIENT_HOST=host.docker.internal +XDEBUG_CLIENT_PORT=9003 +XDEBUG_SESSION=PHPSTORM + +# ============================================================================== +# SESSION HANDLER +# ============================================================================== +# Session storage: files (local) or redis (distributed) +SESSION_SAVE_HANDLER=files +SESSION_SAVE_PATH=/tmp + +# ============================================================================== +# REDIS (Internal - Inside PHP Container) +# ============================================================================== +# Redis runs internally at 127.0.0.1:6379 inside PHP container +REDIS_HOST=127.0.0.1 +REDIS_PORT_INTERNAL=6379 +REDIS_PASSWORD= +REDIS_DB=0 +REDIS_TIMEOUT=5 +REDIS_LOG_FILE=/var/log/redis.log + +# ============================================================================== +# NGINX (Internal - Inside PHP Container) +# ============================================================================== +NGINX_WORKER_PROCESSES=auto +NGINX_WORKER_CONNECTIONS=1024 +NGINX_CLIENT_MAX_BODY_SIZE=100M +NGINX_KEEPALIVE_TIMEOUT=65 + +# ============================================================================== +# COMPOSER +# ============================================================================== +COMPOSER_MEMORY_LIMIT=-1 +COMPOSER_HOME=/root/.composer + +# ============================================================================== +# MEMCACHED (External Service) +# ============================================================================== +MEMCACHED_VERSION=1.6-alpine +MEMCACHED_MEMORY=256 +MEMCACHED_MAX_CONNECTIONS=1024 +MEMCACHED_THREADS=4 +MEMCACHED_MAX_ITEM_SIZE=5m + +# Resource Limits +MEMCACHED_CPU_LIMIT=1.0 +MEMCACHED_CPU_RESERVATION=0.25 +MEMCACHED_MEMORY_TOTAL=512M +MEMCACHED_MEMORY_RESERVATION=256M + +# Health Check +MEMCACHED_HEALTHCHECK_INTERVAL=10s +MEMCACHED_HEALTHCHECK_TIMEOUT=5s +MEMCACHED_HEALTHCHECK_RETRIES=3 +MEMCACHED_HEALTHCHECK_START_PERIOD=10s + +# ============================================================================== +# FEATURES +# ============================================================================== +DEMO_MODE=false +HEALTH_CHECK_INSTALL=false + +# ============================================================================== +# NETWORK +# ============================================================================== +ENABLE_IPV6=false +BRIDGE_NAME=kariricode0 +NETWORK_MTU=1500 +NETWORK_SUBNET=172.20.0.0/16 +NETWORK_GATEWAY=172.20.0.1 + +# ============================================================================== +# LOGGING +# ============================================================================== +LOG_MAX_SIZE=10m +LOG_MAX_FILE=3 +LOG_LEVEL=info + +# ============================================================================== +# HEALTH CHECKS +# ============================================================================== +HEALTHCHECK_INTERVAL=30s +HEALTHCHECK_TIMEOUT=10s +HEALTHCHECK_RETRIES=3 +HEALTHCHECK_START_PERIOD=40s + +# ============================================================================== +# TEMPORARY FILESYSTEM +# ============================================================================== +TMPFS_SIZE=100M + +# ============================================================================== +# TROUBLESHOOTING +# ============================================================================== +# Port conflicts? +# - Change APP_PORT, REDIS_PORT, or MEMCACHED_PORT +# - Run: make diagnose-ports +# - Run: make fix-ports +# +# Performance issues on macOS? +# - Try VOLUME_CONSISTENCY=delegated +# +# Permission errors? +# - Note: Container runs as root, but PHP-FPM/Nginx run as www-data +# - Check file ownership: ls -la +# +# Memory issues? +# - Adjust PHP_MEMORY_LIMIT and resource limits +# +# Session/Redis errors? +# - Use SESSION_SAVE_HANDLER=files for development +# - Use SESSION_SAVE_HANDLER=redis for distributed sessions +# +# PHP-FPM crashes? +# - Check logs: make logs SERVICE=php +# - Verify config: docker compose config +# +# Run diagnostics: +# - make env-check # Validate .env file +# - make diagnose-ports # Check port conflicts +# - make docker-info # Docker environment info +# - make status # Service status +# - make health # Health checks +# ============================================================================== + +# ============================================================================== +# PRODUCTION NOTES +# ============================================================================== +# For production deployment: +# 1. Change APP_ENV=production +# 2. Set APP_DEBUG=false +# 3. Generate strong APP_SECRET: openssl rand -hex 32 +# 4. Set XDEBUG_MODE=off +# 5. Set OPCACHE_VALIDATE_TIMESTAMPS=0 +# 6. Use SESSION_SAVE_HANDLER=redis with password +# 7. Set proper resource limits +# 8. Enable HTTPS/SSL termination +# 9. Use managed Redis/Memcached services +# 10. Implement proper backup strategy +# ============================================================================== diff --git a/.env.example b/.env.example index 681d2d9..3e85f1e 100644 --- a/.env.example +++ b/.env.example @@ -9,11 +9,11 @@ # APPLICATION # ============================================================================== APP_NAME=kariricode-devkit -APP_ENV=development # development|production|testing -APP_DEBUG=true # true|false -APP_SECRET=change-me-in-production # Generate: openssl rand -hex 32 +APP_ENV=development +APP_DEBUG=true +APP_SECRET=change-me-in-production APP_VERSION=dev -SYMFONY_ENV=dev # Symfony environment +SYMFONY_ENV=dev # ============================================================================== # DOCKER & SYSTEM @@ -24,10 +24,10 @@ UID=1000 GID=1000 # Timezone -TZ=UTC # See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +TZ=UTC # Volume consistency (macOS performance) -VOLUME_CONSISTENCY=cached # cached|delegated|consistent +VOLUME_CONSISTENCY=cached # ============================================================================== # PORTS @@ -39,7 +39,7 @@ MEMCACHED_PORT=11211 # ============================================================================== # PHP SERVICE (kariricode/php-api-stack) # ============================================================================== -PHP_STACK_VERSION=dev # dev|latest|1.0.0 +PHP_STACK_VERSION=dev # PHP Configuration PHP_MEMORY_LIMIT=2G @@ -48,17 +48,17 @@ PHP_UPLOAD_MAX_FILESIZE=50M PHP_POST_MAX_SIZE=50M # Resource Limits -PHP_CPU_LIMIT=2.0 # CPU cores limit -PHP_CPU_RESERVATION=0.5 # CPU cores reservation -PHP_MEMORY_RESERVATION=512M # Memory reservation +PHP_CPU_LIMIT=2.0 +PHP_CPU_RESERVATION=0.5 +PHP_MEMORY_RESERVATION=512M # OPcache OPCACHE_ENABLE=1 -OPCACHE_VALIDATE_TIMESTAMPS=1 # 0 for production, 1 for development -OPCACHE_REVALIDATE_FREQ=2 # seconds +OPCACHE_VALIDATE_TIMESTAMPS=1 +OPCACHE_REVALIDATE_FREQ=2 # PHP-FPM Configuration -PHP_FPM_PM=dynamic # static|dynamic|ondemand +PHP_FPM_PM=dynamic PHP_FPM_PM_MAX_CHILDREN=50 PHP_FPM_PM_START_SERVERS=5 PHP_FPM_PM_MIN_SPARE_SERVERS=5 @@ -68,7 +68,7 @@ PHP_FPM_PM_MAX_REQUESTS=500 # ============================================================================== # XDEBUG # ============================================================================== -XDEBUG_MODE=off # off|debug|coverage|profile +XDEBUG_MODE=off XDEBUG_CLIENT_HOST=host.docker.internal XDEBUG_CLIENT_PORT=9003 XDEBUG_SESSION=PHPSTORM @@ -77,16 +77,16 @@ XDEBUG_SESSION=PHPSTORM # SESSION HANDLER # ============================================================================== # Session storage: files (local) or redis (distributed) -SESSION_SAVE_HANDLER=files # files|redis -SESSION_SAVE_PATH=/tmp # For files handler +SESSION_SAVE_HANDLER=files +SESSION_SAVE_PATH=/tmp # ============================================================================== # REDIS (Internal - Inside PHP Container) # ============================================================================== # Redis runs internally at 127.0.0.1:6379 inside PHP container REDIS_HOST=127.0.0.1 -REDIS_PORT_INTERNAL=6379 # Internal Redis port (inside container) -REDIS_PASSWORD= # Empty for development +REDIS_PORT_INTERNAL=6379 +REDIS_PASSWORD= REDIS_DB=0 REDIS_TIMEOUT=5 REDIS_LOG_FILE=/var/log/redis.log @@ -102,17 +102,17 @@ NGINX_KEEPALIVE_TIMEOUT=65 # ============================================================================== # COMPOSER # ============================================================================== -COMPOSER_MEMORY_LIMIT=-1 # -1 for unlimited +COMPOSER_MEMORY_LIMIT=-1 COMPOSER_HOME=/root/.composer # ============================================================================== # MEMCACHED (External Service) # ============================================================================== MEMCACHED_VERSION=1.6-alpine -MEMCACHED_MEMORY=256 # MB +MEMCACHED_MEMORY=256 MEMCACHED_MAX_CONNECTIONS=1024 MEMCACHED_THREADS=4 -MEMCACHED_MAX_ITEM_SIZE=5m # 5 megabytes +MEMCACHED_MAX_ITEM_SIZE=5m # Resource Limits MEMCACHED_CPU_LIMIT=1.0 @@ -144,9 +144,9 @@ NETWORK_GATEWAY=172.20.0.1 # ============================================================================== # LOGGING # ============================================================================== -LOG_MAX_SIZE=10m # Maximum size before rotation -LOG_MAX_FILE=3 # Number of log files to keep -LOG_LEVEL=info # debug|info|notice|warning|error +LOG_MAX_SIZE=10m +LOG_MAX_FILE=3 +LOG_LEVEL=info # ============================================================================== # HEALTH CHECKS @@ -159,24 +159,24 @@ HEALTHCHECK_START_PERIOD=40s # ============================================================================== # TEMPORARY FILESYSTEM # ============================================================================== -TMPFS_SIZE=100M # Size of /tmp tmpfs +TMPFS_SIZE=100M # ============================================================================== # TROUBLESHOOTING # ============================================================================== -# Port conflicts? +# Port conflicts? # - Change APP_PORT, REDIS_PORT, or MEMCACHED_PORT # - Run: make diagnose-ports # - Run: make fix-ports # -# Performance issues on macOS? +# Performance issues on macOS? # - Try VOLUME_CONSISTENCY=delegated # -# Permission errors? +# Permission errors? # - Note: Container runs as root, but PHP-FPM/Nginx run as www-data # - Check file ownership: ls -la # -# Memory issues? +# Memory issues? # - Adjust PHP_MEMORY_LIMIT and resource limits # # Session/Redis errors? @@ -209,4 +209,4 @@ TMPFS_SIZE=100M # Size of /tmp tmpfs # 8. Enable HTTPS/SSL termination # 9. Use managed Redis/Memcached services # 10. Implement proper backup strategy -# ============================================================================== \ No newline at end of file +# ============================================================================== diff --git a/.env.xdebug b/.env.xdebug new file mode 100644 index 0000000..1351c2a --- /dev/null +++ b/.env.xdebug @@ -0,0 +1 @@ +XDEBUG_MODE=debug,coverage diff --git a/.gitattributes b/.gitattributes index 4f2f076..753b72c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,176 +1,23 @@ -# KaririCode DevKit - Git Attributes Configuration -# Ensures consistent line endings and export-ignore for distribution - -# Auto detect text files and normalize line endings to LF * text=auto eol=lf -# ============================================================================ -# SOURCE CODE -# ============================================================================ -*.php text eol=lf diff=php -*.inc text eol=lf -*.module text eol=lf -*.install text eol=lf -*.test text eol=lf -*.theme text eol=lf - -# ============================================================================ -# CONFIGURATION & DATA -# ============================================================================ +*.php text eol=lf *.json text eol=lf -*.yml text eol=lf -*.yaml text eol=lf *.xml text eol=lf -*.ini text eol=lf -*.toml text eol=lf -*.conf text eol=lf -*.config text eol=lf -.env* text eol=lf -*.lock text eol=lf -diff +*.yml text eol=lf +*.neon text eol=lf -# ============================================================================ -# DOCUMENTATION -# ============================================================================ -*.md text eol=lf diff=markdown +*.md text eol=lf *.txt text eol=lf -*.rst text eol=lf -AUTHORS text eol=lf -CHANGELOG text eol=lf -CHANGES text eol=lf -CONTRIBUTING text eol=lf -COPYING text eol=lf -copyright text eol=lf -*COPYRIGHT* text eol=lf -INSTALL text eol=lf -license text eol=lf -LICENSE text eol=lf -NEWS text eol=lf -readme text eol=lf -*README* text eol=lf -TODO text eol=lf - -# ============================================================================ -# SCRIPTS -# ============================================================================ -*.sh text eol=lf -*.bash text eol=lf -*.zsh text eol=lf -*.fish text eol=lf -Makefile text eol=lf -makefile text eol=lf -*.mk text eol=lf - -# ============================================================================ -# DOCKER -# ============================================================================ -Dockerfile text eol=lf -docker-compose*.yml text eol=lf -.dockerignore text eol=lf - -# ============================================================================ -# WEB FILES -# ============================================================================ -*.html text eol=lf diff=html -*.htm text eol=lf diff=html -*.css text eol=lf diff=css -*.scss text eol=lf -*.sass text eol=lf -*.less text eol=lf -*.js text eol=lf -*.mjs text eol=lf -*.ts text eol=lf -*.jsx text eol=lf -*.tsx text eol=lf -*.vue text eol=lf - -# ============================================================================ -# BINARY FILES -# ============================================================================ -# Images -*.png binary -*.jpg binary -*.jpeg binary -*.gif binary -*.ico binary -*.svg binary -*.webp binary -*.bmp binary -*.tiff binary - -# Fonts -*.ttf binary -*.otf binary -*.woff binary -*.woff2 binary -*.eot binary -# Archives -*.zip binary -*.tar binary -*.gz binary -*.bz2 binary -*.7z binary -*.rar binary -*.phar binary - -# Executables -*.exe binary -*.dll binary -*.so binary -*.dylib binary - -# Other -*.pdf binary -*.psd binary -*.ai binary - -# ============================================================================ -# EXPORT-IGNORE (files not included in distribution archives) -# ============================================================================ -# Development files +.gitattributes export-ignore +.gitignore export-ignore +.php-cs-fixer.php export-ignore +phpstan.neon export-ignore +psalm.xml export-ignore +phpunit.xml export-ignore +infection.json export-ignore +phpbench.json export-ignore /.github export-ignore /tests export-ignore -/docs export-ignore -/.editorconfig export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore -/.php-cs-fixer.php export-ignore -/.php-cs-fixer.cache export-ignore -/phpstan.neon export-ignore -/phpstan-baseline.neon export-ignore -/phpunit.xml export-ignore -/phpunit.xml.dist export-ignore -/.phpunit.cache export-ignore -/rector.php export-ignore -/.rector_cache export-ignore -/devkit export-ignore -/docker-compose.yml export-ignore -/Makefile export-ignore -/.env* export-ignore -/coverage export-ignore -/build export-ignore -/.idea export-ignore -/.vscode export-ignore -/install.sh export-ignore - -# CI/CD files -/.github export-ignore -/.gitlab-ci.yml export-ignore -/.travis.yml export-ignore -/azure-pipelines.yml export-ignore -/.circleci export-ignore - -# Documentation files -/README.md export-ignore -/CHANGELOG.md export-ignore -/CONTRIBUTING.md export-ignore -/CODE_OF_CONDUCT.md export-ignore -/SECURITY.md export-ignore -/UPGRADING.md export-ignore - -# PHP specific -/composer.lock export-ignore - -# Git files -/.gitattributes export-ignore -/.gitignore export-ignore \ No newline at end of file +/benchmarks export-ignore +/docs export-ignore \ No newline at end of file diff --git a/.gitignore b/.gitignore index bb22189..f811d09 100644 --- a/.gitignore +++ b/.gitignore @@ -1,195 +1,46 @@ -# ============================================================================ -# KaririCode DevKit - Git Ignore Configuration -# ============================================================================ -# Comprehensive ignore rules for development environment -# ============================================================================ - -# ============================================================================ -# VENDOR & DEPENDENCIES -# ============================================================================ +# Composer /vendor/ -/composer.lock -composer.phar -/node_modules/ -package-lock.json -yarn.lock +composer.lock + +# PHPUnit +.phpunit.cache/ +.phpunit.result.cache +/coverage/ +/reports/ + +# PHPStan +/var/cache/phpstan/ +.phpstan.cache -# ============================================================================ -# ENVIRONMENT & SECRETS -# ============================================================================ -.env -.env.local -.env.*.local -.env.backup -.env.xdebug -*.key -*.pem +# Psalm +psalm-baseline.xml +.psalm/ -# ============================================================================ -# IDE & EDITORS -# ============================================================================ -# PHPStorm / IntelliJ -.idea/ -*.iml -*.iws -*.ipr +# PHP-CS-Fixer +.php-cs-fixer.cache -# VSCode -.vscode/ -*.code-workspace +# Infection +/var/cache/infection/ +infection.log +infection.html +infection-summary.log +infection-debug.log +infection-per-mutator.md -# Sublime Text -*.sublime-project -*.sublime-workspace +# PHPBench +.phpbench/ +benchmarks/ -# Vim +# IDEs +/.idea/ *.swp *.swo *~ - -# Emacs -*~ -\#*\# -.\#* - -# NetBeans -nbproject/ - -# ============================================================================ -# OPERATING SYSTEM FILES -# ============================================================================ -# macOS .DS_Store -.AppleDouble -.LSOverride -._* -.Spotlight-V100 -.Trashes - -# Windows -Thumbs.db -ehthumbs.db -Desktop.ini -$RECYCLE.BIN/ -*.lnk - -# Linux -.directory -.Trash-* -# ============================================================================ -# PHP TESTING & COVERAGE -# ============================================================================ -/.phpunit.cache/ -/coverage/ +# Build artifacts /build/ -/.phpunit.result.cache -/test-results/ - -# ============================================================================ -# QUALITY TOOLS CACHE -# ============================================================================ -.php-cs-fixer.cache -/.php-cs-fixer.cache -.phpstan.cache -/.phpstan.cache -/.rector_cache/ -/.psalm_cache/ -/metrics/ - -# ============================================================================ -# LOGS & TEMPORARY FILES -# ============================================================================ -*.log -*.tmp -*.temp -*.cache -*.bak -*.old -*.orig -*.swp -/logs/ -/tmp/ - -# ============================================================================ -# DOCKER -# ============================================================================ -/docker-compose.override.yml -/.docker/ -!docker/ - -# ============================================================================ -# PUBLIC DIRECTORY -# ============================================================================ -# Created by php-api-stack image for demo/testing -/public/ - -# ============================================================================ -# DOCUMENTATION BUILD -# ============================================================================ -/docs/_build/ -/docs/.phpdoc/ -/.phpdoc/ -/phpdoc/ - -# ============================================================================ -# ARCHIVES & DISTRIBUTIONS -# ============================================================================ -*.zip -*.tar -*.tar.gz -*.rar -*.7z -*.phar - -# ============================================================================ -# GENERATED FILES -# ============================================================================ /dist/ -/output/ -/generated/ - -# ============================================================================ -# SECURITY SCAN RESULTS -# ============================================================================ -/security-checker.cache -/trivy-results.json -/snyk-results.json - -# ============================================================================ -# CI/CD ARTIFACTS -# ============================================================================ -/.github/workflows/*-local.yml -/.gitlab-ci-local.yml - -# ============================================================================ -# PERFORMANCE & PROFILING -# ============================================================================ -*.cachegrind -*.xhprof -/profiler/ -/blackfire/ -# ============================================================================ -# DATABASE -# ============================================================================ -*.sqlite -*.sqlite3 -*.db - -# ============================================================================ -# SESSION & CACHE -# ============================================================================ -/storage/framework/cache/* -/storage/framework/sessions/* -/storage/framework/views/* -/storage/logs/* - -# ============================================================================ -# MISC -# ============================================================================ -auth.json -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* \ No newline at end of file +# Logs +*.log diff --git a/.make/core/Makefile.functions.mk b/.make/core/Makefile.functions.mk index 81bb93c..4dcac01 100644 --- a/.make/core/Makefile.functions.mk +++ b/.make/core/Makefile.functions.mk @@ -28,7 +28,7 @@ endef # --- Verificação de Arquivo --- define check_file @test -f $(1) || (echo "$(RED)✗ $(2) not found$(RESET)" && exit 1) -endef +endef # --- Criação de Diretório --- define ensure_dir @@ -40,7 +40,7 @@ define pipeline_header @echo -e "$(BOLD)$(CYAN)╔════════════════════════════════════════════════════════╗$(RESET)" @echo -e "$(BOLD)$(CYAN)║ $(1)$(RESET)" @echo -e "$(BOLD)$(CYAN)╚════════════════════════════════════════════════════════╝$(RESET)" - @echo "" + @echo -e "" endef # --- Verificação de Branch Git --- diff --git a/.make/docker/Makefile.docker-compose.mk b/.make/docker/Makefile.docker-compose.mk index 395da03..45b4aa7 100644 --- a/.make/docker/Makefile.docker-compose.mk +++ b/.make/docker/Makefile.docker-compose.mk @@ -95,7 +95,7 @@ check-ports: clean-docker check-docker-ports ## Check for port conflicts (includ diagnose-ports: ## Detailed port conflict diagnosis @echo -e "$(BOLD)$(CYAN)Port Conflict Diagnosis$(RESET)" @echo -e "$(BLUE)╔════════════════════════════════════════════════════════╗$(RESET)" - @echo "" + @echo -e "" @bash -c ' \ if [ -f .env ]; then \ source .env 2>/dev/null || true; \ @@ -138,7 +138,7 @@ diagnose-ports: ## Detailed port conflict diagnosis fix-ports: ## Automatically fix port conflicts (interactive) @echo -e "$(YELLOW)⚠ This will attempt to free up conflicting ports$(RESET)" @echo -e "$(YELLOW) Docker containers and processes will be terminated$(RESET)" - @echo "" + @echo -e "" @bash -c ' \ read -p "Continue? [y/N] " -n 1 -r; \ echo; \ @@ -175,7 +175,7 @@ _do_fix_ports: fi; \ done \ ' - @echo "" + @echo -e "" @$(MAKE) --no-print-directory check-ports kill-port: ## Kill process using specific port (usage: make kill-port PORT=11211) @@ -209,7 +209,7 @@ kill-port: ## Kill process using specific port (usage: make kill-port PORT=11211 port-scan: ## Scan common ports for conflicts @echo -e "$(BOLD)$(CYAN)Port Scanner$(RESET)" @echo -e "$(BLUE)╔════════════════════════════════════════════════════════╗$(RESET)" - @echo "" + @echo -e "" @for port in 80 443 3000 3306 5432 6379 8000 8080 8089 9000 11211 27017; do \ if lsof -Pi :$$port -sTCP:LISTEN -t >/dev/null 2>&1; then \ PROCESS=$$(lsof -Pi :$$port -sTCP:LISTEN -t | head -1); \ @@ -219,7 +219,7 @@ port-scan: ## Scan common ports for conflicts echo -e "$(GREEN)✓ Port $$port: Available$(RESET)"; \ fi; \ done - @echo "" + @echo -e "" @echo -e "$(BLUE)╚════════════════════════════════════════════════════════╝$(RESET)" # ============================================================================== @@ -232,7 +232,7 @@ up: ## Start Docker Compose services @echo -e "$(BLUE)→ Starting Docker Compose services...$(RESET)" @if [ ! -f .env ]; then \ echo -e "$(YELLOW)⚠ .env not found, copying from .env.example...$(RESET)"; \ - cp .env.example .env 2>/dev/null || echo -e "$(RED)✗ .env.example not found$(RESET)"; \ + cp .env.example .env 2>/dev/null || echo "$(RED)✗ .env.example not found$(RESET)"; \ fi @docker compose --profile development up -d || { \ echo ""; \ @@ -414,7 +414,7 @@ inspect-php: ## Inspect PHP container @echo -e "$(BOLD)$(CYAN)PHP Container Inspection$(RESET)" @echo -e "$(BLUE)╔════════════════════════════════════════════════════════╗$(RESET)" @docker compose exec php php -v - @echo "" + @echo -e "" @docker compose exec php php -m @echo -e "$(BLUE)╚════════════════════════════════════════════════════════╝$(RESET)" @@ -428,4 +428,4 @@ env-check: ## Verify environment variables echo -e "$(RED)✗ .env file not found$(RESET)"; \ echo -e "$(YELLOW) Run: cp .env.example .env$(RESET)"; \ fi - @echo -e "$(BLUE)╚════════════════════════════════════════════════════════╝$(RESET)" \ No newline at end of file + @echo -e "$(BLUE)╚════════════════════════════════════════════════════════╝$(RESET)" diff --git a/.make/docker/Makefile.docker-core.mk b/.make/docker/Makefile.docker-core.mk index 4fb142a..d7d8249 100644 --- a/.make/docker/Makefile.docker-core.mk +++ b/.make/docker/Makefile.docker-core.mk @@ -11,15 +11,15 @@ # ============================================================================== docker-shell: ## Open interactive shell in Docker - @echo "$(BLUE)→ Opening Docker shell ($(DOCKER_IMAGE))...$(RESET)" + @echo -e "$(BLUE)→ Opening Docker shell ($(DOCKER_IMAGE))...$(RESET)" @$(DOCKER_RUN_IT) $(DOCKER_IMAGE) /bin/bash docker-composer: ## Run composer in Docker (usage: make docker-composer CMD="install") $(call validate_param,CMD,make docker-composer CMD='install') - @echo "$(BLUE)→ Running composer $(CMD) in Docker...$(RESET)" + @echo -e "$(BLUE)→ Running composer $(CMD) in Docker...$(RESET)" @$(DOCKER_RUN) $(DOCKER_IMAGE) composer $(CMD) docker-php: ## Run PHP command in Docker (usage: make docker-php CMD="-v") $(call validate_param,CMD,make docker-php CMD='-v') - @echo "$(BLUE)→ Running php $(CMD) in Docker...$(RESET)" + @echo -e "$(BLUE)→ Running php $(CMD) in Docker...$(RESET)" @$(DOCKER_RUN) $(DOCKER_IMAGE) php $(CMD) diff --git a/.make/docker/Makefile.docker-image.mk b/.make/docker/Makefile.docker-image.mk index 37f598f..c52b34a 100644 --- a/.make/docker/Makefile.docker-image.mk +++ b/.make/docker/Makefile.docker-image.mk @@ -19,23 +19,23 @@ .PHONY: docker-pull docker-info docker-clean docker-pull: ## Pull Docker image from registry - @echo "$(BLUE)→ Pulling Docker image $(DOCKER_IMAGE)...$(RESET)" + @echo -e "$(BLUE)→ Pulling Docker image $(DOCKER_IMAGE)...$(RESET)" @docker pull $(DOCKER_IMAGE) - @echo "$(GREEN)✓ Docker image pulled$(RESET)" + @echo -e "$(GREEN)✓ Docker image pulled$(RESET)" docker-info: ## Show Docker environment info - @echo "$(BOLD)$(CYAN)Docker Environment Information$(RESET)" - @echo "$(BLUE)═══════════════════════════════════════════════════════════$(RESET)" - @echo "Docker Image: $(DOCKER_IMAGE)" - @echo "Mount Point: $(PWD):/app" - @echo "" - @echo "$(BOLD)$(CYAN)Container PHP Info$(RESET)" - @echo "$(BLUE)═══════════════════════════════════════════════════════════$(RESET)" + @echo -e "$(BOLD)$(CYAN)Docker Environment Information$(RESET)" + @echo -e "$(BLUE)═══════════════════════════════════════════════════════════$(RESET)" + @echo -e "Docker Image: $(DOCKER_IMAGE)" + @echo -e "Mount Point: $(PWD):/app" + @echo -e "" + @echo -e "$(BOLD)$(CYAN)Container PHP Info$(RESET)" + @echo -e "$(BLUE)═══════════════════════════════════════════════════════════$(RESET)" @$(DOCKER_RUN) $(DOCKER_IMAGE) php -v - @echo "" + @echo -e "" @$(DOCKER_RUN) $(DOCKER_IMAGE) composer --version docker-clean: ## Clean Docker resources - @echo "$(BLUE)→ Cleaning Docker resources...$(RESET)" + @echo -e "$(BLUE)→ Cleaning Docker resources...$(RESET)" @docker system prune -f - @echo "$(GREEN)✓ Docker cleanup complete$(RESET)" + @echo -e "$(GREEN)✓ Docker cleanup complete$(RESET)" diff --git a/.make/docker/Makefile.docker-qa.mk b/.make/docker/Makefile.docker-qa.mk index b99f9a5..b4e99a0 100644 --- a/.make/docker/Makefile.docker-qa.mk +++ b/.make/docker/Makefile.docker-qa.mk @@ -22,9 +22,9 @@ docker-test-integration: ## Run integration tests in Docker $(call docker_exec_make,test-integration) docker-coverage: ## Generate coverage in Docker - @echo "$(BLUE)→ Generating coverage in Docker...$(RESET)" + @echo -e "$(BLUE)→ Generating coverage in Docker...$(RESET)" @$(DOCKER_RUN) $(DOCKER_IMAGE) make coverage - @echo "$(GREEN)✓ Coverage report: $(COVERAGE_DIR)/html/index.html$(RESET)" + @echo -e "$(GREEN)✓ Coverage report: $(COVERAGE_DIR)/html/index.html$(RESET)" docker-analyse: ## Run static analysis in Docker $(call docker_exec_make,analyse) @@ -49,16 +49,16 @@ docker-lint: ## Lint PHP files in Docker # ============================================================================== docker-ci: ## Run CI pipeline in Docker - $(call pipeline_header,"Docker CI Pipeline (Isolated Environment) ") + $(call pipeline_header,"Docker CI Pipeline Isolated Environment") $(call docker_exec_make,ci) - @echo "" - @echo "$(BOLD)$(GREEN)✓ Docker CI pipeline completed$(RESET)" + @echo -e "" + @echo -e "$(BOLD)$(GREEN)✓ Docker CI pipeline completed$(RESET)" docker-ci-full: ## Run full CI pipeline in Docker - $(call pipeline_header,"Docker Full CI Pipeline (Isolated Environment) ") + $(call pipeline_header,"Docker Full CI Pipeline Isolated Environment") $(call docker_exec_make,ci-full) - @echo "" - @echo "$(BOLD)$(GREEN)✓ Docker full CI pipeline completed$(RESET)" + @echo -e "" + @echo -e "$(BOLD)$(GREEN)✓ Docker full CI pipeline completed$(RESET)" docker-bench: ## Run benchmarks in Docker $(call docker_exec_make,bench) diff --git a/.make/docker/Makefile.docker-tools.mk b/.make/docker/Makefile.docker-tools.mk index f9862ac..3e71c97 100644 --- a/.make/docker/Makefile.docker-tools.mk +++ b/.make/docker/Makefile.docker-tools.mk @@ -12,7 +12,7 @@ # ============================================================================== docker-htop: ## Run htop utility in Docker - @echo "$(BLUE)→ Running htop in Docker...$(RESET)" + @echo -e "$(BLUE)→ Running htop in Docker...$(RESET)" @$(DOCKER_RUN_IT) $(DOCKER_IMAGE) htop # ============================================================================== @@ -21,12 +21,12 @@ docker-htop: ## Run htop utility in Docker docker-vim: ## Edit files with vim in Docker (usage: make docker-vim CMD="src/file.php") $(call validate_param,CMD,make docker-vim CMD='src/file.php') - @echo "$(BLUE)→ Running vim $(CMD) in Docker...$(RESET)" + @echo -e "$(BLUE)→ Running vim $(CMD) in Docker...$(RESET)" @$(DOCKER_RUN_IT) $(DOCKER_IMAGE) vim $(CMD) docker-less: ## View files with less in Docker (usage: make docker-less CMD="README.md") $(call validate_param,CMD,make docker-less CMD='README.md') - @echo "$(BLUE)→ Running less $(CMD) in Docker...$(RESET)" + @echo -e "$(BLUE)→ Running less $(CMD) in Docker...$(RESET)" @$(DOCKER_RUN_IT) $(DOCKER_IMAGE) less $(CMD) # ============================================================================== @@ -35,12 +35,12 @@ docker-less: ## View files with less in Docker (usage: make docker-less CMD="REA docker-jq: ## Run jq utility in Docker (usage: make docker-jq CMD="'.version' composer.json") $(call validate_param,CMD,make docker-jq CMD="'.version' composer.json") - @echo "$(BLUE)→ Running jq $(CMD) in Docker...$(RESET)" + @echo -e "$(BLUE)→ Running jq $(CMD) in Docker...$(RESET)" @$(DOCKER_RUN) $(DOCKER_IMAGE) sh -c "jq $(CMD)" docker-yq: ## Run yq utility in Docker (usage: make docker-yq CMD="'.services' docker-compose.yml") $(call validate_param,CMD,make docker-yq CMD="'.services' docker-compose.yml") - @echo "$(BLUE)→ Running yq $(CMD) in Docker...$(RESET)" + @echo -e "$(BLUE)→ Running yq $(CMD) in Docker...$(RESET)" @$(DOCKER_RUN) $(DOCKER_IMAGE) sh -c "yq $(CMD)" # ============================================================================== @@ -48,12 +48,12 @@ docker-yq: ## Run yq utility in Docker (usage: make docker-yq CMD="'.services' d # ============================================================================== docker-lsof: ## Run lsof utility in Docker (usage: make docker-lsof CMD="-i") - @echo "$(BLUE)→ Running lsof $(CMD) in Docker...$(RESET)" + @echo -e "$(BLUE)→ Running lsof $(CMD) in Docker...$(RESET)" @$(DOCKER_RUN_IT) --cap-add=SYS_PTRACE --cap-add=SYS_ADMIN $(DOCKER_IMAGE) lsof $(CMD) docker-strace: ## Run strace utility in Docker (usage: make docker-strace CMD="php -v") $(call validate_param,CMD,make docker-strace CMD='php -v') - @echo "$(BLUE)→ Running strace $(CMD) in Docker...$(RESET)" + @echo -e "$(BLUE)→ Running strace $(CMD) in Docker...$(RESET)" @$(DOCKER_RUN_IT) --cap-add=SYS_PTRACE $(DOCKER_IMAGE) strace $(CMD) # ============================================================================== @@ -62,10 +62,10 @@ docker-strace: ## Run strace utility in Docker (usage: make docker-strace CMD="p docker-ip: ## Run iproute2 utility in Docker (usage: make docker-ip CMD="addr") $(call validate_param,CMD,make docker-ip CMD='addr') - @echo "$(BLUE)→ Running ip $(CMD) in Docker...$(RESET)" + @echo -e "$(BLUE)→ Running ip $(CMD) in Docker...$(RESET)" @$(DOCKER_RUN) $(DOCKER_IMAGE) ip $(CMD) docker-nc: ## Run netcat utility in Docker (usage: make docker-nc CMD="-vz localhost 9000") $(call validate_param,CMD,make docker-nc CMD='-vz localhost 9000') - @echo "$(BLUE)→ Running netcat $(CMD) in Docker...$(RESET)" + @echo -e "$(BLUE)→ Running netcat $(CMD) in Docker...$(RESET)" @$(DOCKER_RUN_IT) $(DOCKER_IMAGE) nc $(CMD) diff --git a/.make/local/Makefile.helpers.mk b/.make/local/Makefile.helpers.mk index 43552e1..e77a686 100644 --- a/.make/local/Makefile.helpers.mk +++ b/.make/local/Makefile.helpers.mk @@ -164,13 +164,13 @@ info: ## Show PHP and project information @echo -e "" @echo -e "$(BOLD)$(CYAN)Installed Tools$(RESET)" @echo -e "$(BLUE)═══════════════════════════════════════════════════════════$(RESET)" - @test -f $(PHPUNIT) && echo -e "PHPUnit: ✓" || echo -e "PHPUnit: ✗" - @test -f $(PHPSTAN) && echo -e "PHPStan: ✓" || echo -e "PHPStan: ✗" - @test -f $(PSALM) && echo -e "Psalm: ✓" || echo -e "Psalm: ✗" - @test -f $(PHPCS) && echo -e "PHPCS: ✓" || echo -e "PHPCS: ✗" - @test -f $(PHP_CS_FIXER) && echo -e "PHP-CS-Fixer: ✓" || echo -e "PHP-CS-Fixer: ✗" - @test -f $(INFECTION) && echo -e "Infection: ✓" || echo -e "Infection: ✗" - @test -f $(PHPBENCH) && echo -e "PHPBench: ✓" || echo -e "PHPBench: ✗" + @test -f $(PHPUNIT) && echo "PHPUnit: ✓" || echo "PHPUnit: ✗" + @test -f $(PHPSTAN) && echo "PHPStan: ✓" || echo "PHPStan: ✗" + @test -f $(PSALM) && echo "Psalm: ✓" || echo "Psalm: ✗" + @test -f $(PHPCS) && echo "PHPCS: ✓" || echo "PHPCS: ✗" + @test -f $(PHP_CS_FIXER) && echo "PHP-CS-Fixer: ✓" || echo "PHP-CS-Fixer: ✗" + @test -f $(INFECTION) && echo "Infection: ✓" || echo "Infection: ✗" + @test -f $(PHPBENCH) && echo "PHPBench: ✓" || echo "PHPBench: ✗" # ============================================================================== # RELEASE MANAGEMENT @@ -188,7 +188,7 @@ tag: ## Create a new git tag (usage: make tag VERSION=1.0.0) release: cd ## Prepare release (run full CD pipeline) @echo -e "$(BOLD)$(GREEN)✓ Release preparation complete$(RESET)" - @echo "" + @echo -e "" @echo -e "$(CYAN)Next steps:$(RESET)" @echo -e " 1. Update CHANGELOG.md" @echo -e " 2. Update version in composer.json" diff --git a/.make/local/Makefile.qa.mk b/.make/local/Makefile.qa.mk index 85f809f..822cd14 100644 --- a/.make/local/Makefile.qa.mk +++ b/.make/local/Makefile.qa.mk @@ -11,115 +11,115 @@ # ============================================================================== test: ## Run PHPUnit tests - @echo "$(BLUE)→ Running tests...$(RESET)" + @echo -e "$(BLUE)→ Running tests...$(RESET)" @$(PHPUNIT) --colors=always --testdox - @echo "$(GREEN)✓ Tests passed$(RESET)" + @echo -e "$(GREEN)✓ Tests passed$(RESET)" test-unit: ## Run unit tests only - @echo "$(BLUE)→ Running unit tests...$(RESET)" + @echo -e "$(BLUE)→ Running unit tests...$(RESET)" @$(PHPUNIT) --colors=always --testdox --testsuite=Unit - @echo "$(GREEN)✓ Unit tests passed$(RESET)" + @echo -e "$(GREEN)✓ Unit tests passed$(RESET)" test-integration: ## Run integration tests only - @echo "$(BLUE)→ Running integration tests...$(RESET)" + @echo -e "$(BLUE)→ Running integration tests...$(RESET)" @$(PHPUNIT) --colors=always --testdox --testsuite=Integration - @echo "$(GREEN)✓ Integration tests passed$(RESET)" + @echo -e "$(GREEN)✓ Integration tests passed$(RESET)" test-functional: ## Run functional tests only - @echo "$(BLUE)→ Running functional tests...$(RESET)" + @echo -e "$(BLUE)→ Running functional tests...$(RESET)" @$(PHPUNIT) --colors=always --testdox --testsuite=Functional - @echo "$(GREEN)✓ Functional tests passed$(RESET)" + @echo -e "$(GREEN)✓ Functional tests passed$(RESET)" coverage: ## Generate code coverage report - @echo "$(BLUE)→ Generating code coverage report...$(RESET)" + @echo -e "$(BLUE)→ Generating code coverage report...$(RESET)" @mkdir -p $(COVERAGE_DIR) @XDEBUG_MODE=coverage $(PHPUNIT) --coverage-html $(COVERAGE_DIR)/html \ --coverage-clover $(COVERAGE_DIR)/clover.xml \ --coverage-text=$(COVERAGE_DIR)/coverage.txt - @echo "$(GREEN)✓ Coverage report generated: $(COVERAGE_DIR)/html/index.html$(RESET)" + @echo -e "$(GREEN)✓ Coverage report generated: $(COVERAGE_DIR)/html/index.html$(RESET)" coverage-text: ## Show coverage in terminal - @echo "$(BLUE)→ Generating text coverage...$(RESET)" + @echo -e "$(BLUE)→ Generating text coverage...$(RESET)" @XDEBUG_MODE=coverage $(PHPUNIT) --coverage-text mutation: ## Run mutation testing - @echo "$(BLUE)→ Running mutation tests...$(RESET)" + @echo -e "$(BLUE)→ Running mutation tests...$(RESET)" @mkdir -p $(CACHE_DIR)/infection @XDEBUG_MODE=coverage $(PHP) -d pcov.enabled=0 $(INFECTION) --threads=4 --min-msi=80 --min-covered-msi=90 --show-mutations - @echo "$(GREEN)✓ Mutation testing complete$(RESET)" + @echo -e "$(GREEN)✓ Mutation testing complete$(RESET)" mutation-report: ## Generate mutation testing report - @echo "$(BLUE)→ Generating mutation report...$(RESET)" + @echo -e "$(BLUE)→ Generating mutation report...$(RESET)" @XDEBUG_MODE=coverage $(PHP) -d pcov.enabled=0 $(INFECTION) --threads=4 --min-msi=80 --min-covered-msi=90 \ --log-verbosity=all --show-mutations - @echo "$(GREEN)✓ Report generated: infection.html$(RESET)" + @echo -e "$(GREEN)✓ Report generated: infection.html$(RESET)" # ============================================================================== # STATIC ANALYSIS # ============================================================================== analyse: ## Run all static analysis tools - @echo "$(BLUE)→ Running static analysis...$(RESET)" + @echo -e "$(BLUE)→ Running static analysis...$(RESET)" @$(MAKE) phpstan @$(MAKE) psalm @$(MAKE) cs-check - @echo "$(GREEN)✓ All analysis passed$(RESET)" + @echo -e "$(GREEN)✓ All analysis passed$(RESET)" phpstan: ## Run PHPStan analysis - @echo "$(BLUE)→ Running PHPStan...$(RESET)" + @echo -e "$(BLUE)→ Running PHPStan...$(RESET)" @mkdir -p $(CACHE_DIR)/phpstan @if [ -n "$$(find $(SRC_DIR) -name '*.php' 2>/dev/null)" ]; then \ $(PHPSTAN) analyse $(SRC_DIR) --level=max --memory-limit=512M && \ - echo "$(GREEN)✓ PHPStan analysis passed$(RESET)"; \ + echo -e "$(GREEN)✓ PHPStan analysis passed$(RESET)"; \ else \ - echo "$(YELLOW)⚠ No PHP files found in $(SRC_DIR), skipping PHPStan$(RESET)"; \ + echo -e "$(YELLOW)⚠ No PHP files found in $(SRC_DIR), skipping PHPStan$(RESET)"; \ fi phpstan-baseline: ## Generate PHPStan baseline - @echo "$(BLUE)→ Generating PHPStan baseline...$(RESET)" + @echo -e "$(BLUE)→ Generating PHPStan baseline...$(RESET)" @$(PHPSTAN) analyse $(SRC_DIR) --level=max --generate-baseline - @echo "$(GREEN)✓ Baseline generated: phpstan-baseline.neon$(RESET)" + @echo -e "$(GREEN)✓ Baseline generated: phpstan-baseline.neon$(RESET)" psalm: ## Run Psalm analysis - @echo "$(BLUE)→ Running Psalm...$(RESET)" + @echo -e "$(BLUE)→ Running Psalm...$(RESET)" @$(PSALM) --show-info=true --stats --no-cache - @echo "$(GREEN)✓ Psalm analysis passed$(RESET)" + @echo -e "$(GREEN)✓ Psalm analysis passed$(RESET)" psalm-baseline: ## Generate Psalm baseline - @echo "$(BLUE)→ Generating Psalm baseline...$(RESET)" + @echo -e "$(BLUE)→ Generating Psalm baseline...$(RESET)" @$(PSALM) --set-baseline=psalm-baseline.xml - @echo "$(GREEN)✓ Baseline generated: psalm-baseline.xml$(RESET)" + @echo -e "$(GREEN)✓ Baseline generated: psalm-baseline.xml$(RESET)" psalm-taint: ## Run Psalm taint analysis - @echo "$(BLUE)→ Running Psalm taint analysis...$(RESET)" + @echo -e "$(BLUE)→ Running Psalm taint analysis...$(RESET)" @$(PSALM) --taint-analysis - @echo "$(GREEN)✓ Taint analysis complete$(RESET)" + @echo -e "$(GREEN)✓ Taint analysis complete$(RESET)" # ============================================================================== # CODE STYLE & FORMATTING # ============================================================================== cs-check: ## Check coding standards (PHPCS) - @echo "$(BLUE)→ Checking coding standards...$(RESET)" + @echo -e "$(BLUE)→ Checking coding standards...$(RESET)" @$(PHPCS) --standard=phpcs.xml --colors $(SRC_DIR) $(TEST_DIR) - @echo "$(GREEN)✓ Coding standards check passed$(RESET)" + @echo -e "$(GREEN)✓ Coding standards check passed$(RESET)" cbf-fix: ## Fix coding standards (PHPCS) - @echo "$(BLUE)→ Fixing coding standards...$(RESET)" + @echo -e "$(BLUE)→ Fixing coding standards...$(RESET)" @$(PHPCBF) --standard=phpcs.xml --colors $(SRC_DIR) $(TEST_DIR) - @echo "$(GREEN)✓ Coding standards fixed$(RESET)" + @echo -e "$(GREEN)✓ Coding standards fixed$(RESET)" format: ## Format code with PHP-CS-Fixer - @echo "$(BLUE)→ Formatting code...$(RESET)" + @echo -e "$(BLUE)→ Formatting code...$(RESET)" @$(PHP_CS_FIXER) fix --config=.php-cs-fixer.php --verbose --diff @$(MAKE) cbf-fix - @echo "$(GREEN)✓ Code formatted$(RESET)" + @echo -e "$(GREEN)✓ Code formatted$(RESET)" format-dry: ## Show formatting changes without applying - @echo "$(BLUE)→ Dry-run code formatting...$(RESET)" + @echo -e "$(BLUE)→ Dry-run code formatting...$(RESET)" @$(PHP_CS_FIXER) fix --config=.php-cs-fixer.php --verbose --diff --dry-run lint: ## Lint PHP files for syntax errors - @echo "$(BLUE)→ Linting PHP files...$(RESET)" + @echo -e "$(BLUE)→ Linting PHP files...$(RESET)" @find $(SRC_DIR) $(TEST_DIR) -name "*.php" -print0 | xargs -0 -n1 $(PHP) -l > /dev/null - @echo "$(GREEN)✓ All PHP files are valid$(RESET)" + @echo -e "$(GREEN)✓ All PHP files are valid$(RESET)" diff --git a/.make/pipeline/Makefile.orchestration.mk b/.make/pipeline/Makefile.orchestration.mk index e88c7a4..c31e534 100644 --- a/.make/pipeline/Makefile.orchestration.mk +++ b/.make/pipeline/Makefile.orchestration.mk @@ -8,7 +8,7 @@ # --- Quality Checks --- check: lint analyse test ## Run all quality checks - @echo "$(GREEN)✓ All quality checks passed$(RESET)" + @echo -e "$(GREEN)✓ All quality checks passed$(RESET)" # --- CI Pipeline --- ci: ## Run CI pipeline (fast checks) @@ -19,7 +19,7 @@ ci: ## Run CI pipeline (fast checks) @$(MAKE) --no-print-directory phpstan @$(MAKE) --no-print-directory psalm @$(MAKE) --no-print-directory test - @echo "$(BOLD)$(GREEN)✓ CI pipeline completed successfully$(RESET)" + @echo -e "$(BOLD)$(GREEN)✓ CI pipeline completed successfully$(RESET)" # --- Full CI Pipeline --- ci-full: ## Run full CI pipeline (with coverage) @@ -34,20 +34,20 @@ ci-full: ## Run full CI pipeline (with coverage) @$(MAKE) --no-print-directory test @$(MAKE) --no-print-directory coverage @$(MAKE) --no-print-directory mutation - @echo "$(BOLD)$(GREEN)✓ Full CI pipeline completed successfully$(RESET)" + @echo -e "$(BOLD)$(GREEN)✓ Full CI pipeline completed successfully$(RESET)" # --- CD Pipeline --- cd: ## Run CD pipeline (release preparation) $(call pipeline_header,"KaririCode\\DevKit CD Pipeline") @$(MAKE) --no-print-directory ci-full @$(MAKE) --no-print-directory bench - @echo "$(BOLD)$(GREEN)✓ CD pipeline completed - Ready for release$(RESET)" + @echo -e "$(BOLD)$(GREEN)✓ CD pipeline completed - Ready for release$(RESET)" # --- Pre-commit Hook --- pre-commit: ## Run pre-commit checks - @echo "$(BLUE)→ Running pre-commit checks...$(RESET)" + @echo -e "$(BLUE)→ Running pre-commit checks...$(RESET)" @$(MAKE) --no-print-directory format @$(MAKE) --no-print-directory lint @$(MAKE) --no-print-directory analyse @$(MAKE) --no-print-directory test-unit - @echo "$(GREEN)✓ Pre-commit checks passed$(RESET)" + @echo -e "$(GREEN)✓ Pre-commit checks passed$(RESET)" diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index f8904d9..fb451a1 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -3,86 +3,98 @@ declare(strict_types=1); /** - * KaririCode DevKit - PHP CS Fixer Configuration + * PHP-CS-Fixer Configuration for KaririCode\Parser. * - * Professional code style configuration following PSR-12 and best practices. - * This configuration ensures consistency across all KaririCode Framework components. + * Ensures PSR-12 compliance while preserving premium documentation. * - * @see https://cs.symfony.com/doc/rules/index.html - * @see https://www.php-fig.org/psr/psr-12/ + * @package KaririCode\Parser + * @author Walmir Silva + * @since 1.0.0 */ -use PhpCsFixer\Config; -use PhpCsFixer\Finder; - -$finder = (new Finder()) +$finder = PhpCsFixer\Finder::create() ->in([ __DIR__ . '/src', __DIR__ . '/tests', ]) ->name('*.php') - ->notName('*.blade.php') ->ignoreDotFiles(true) - ->ignoreVCS(true); + ->ignoreVCS(true) + ->notPath('vendor'); -return (new Config()) +return (new PhpCsFixer\Config()) ->setRiskyAllowed(true) ->setRules([ - // PSR Standards + // ==================================================================== + // BASE RULE SETS + // ==================================================================== '@PSR12' => true, - '@PSR12:risky' => true, - - // Strict Types - 'declare_strict_types' => true, - 'strict_param' => true, - 'strict_comparison' => true, - - // Array Notation + '@PHP8x3Migration' => true, // Usar PHP83 em vez de PHP84 (mais estável) + + // ==================================================================== + // CRITICAL: COMMENT PRESERVATION RULES + // ==================================================================== + 'no_empty_phpdoc' => false, + 'no_superfluous_phpdoc_tags' => false, + 'phpdoc_no_useless_inheritdoc' => false, + 'phpdoc_no_access' => false, + 'phpdoc_no_package' => false, + 'phpdoc_summary' => false, + 'phpdoc_order' => false, + 'phpdoc_separation' => false, + 'phpdoc_tag_type' => false, + 'phpdoc_to_comment' => false, + 'phpdoc_add_missing_param_annotation' => false, + 'no_blank_lines_after_phpdoc' => false, + 'phpdoc_align' => false, + 'phpdoc_indent' => false, + 'phpdoc_trim' => false, + 'no_trailing_whitespace_in_comment' => false, + 'single_line_comment_style' => false, + 'multiline_comment_opening_closing' => false, + 'comment_to_phpdoc' => false, + 'no_empty_comment' => false, + + // ==================================================================== + // ARRAYS + // ==================================================================== 'array_syntax' => ['syntax' => 'short'], - 'no_multiline_whitespace_around_double_arrow' => true, - 'trim_array_spaces' => true, + 'no_whitespace_before_comma_in_array' => true, 'whitespace_after_comma_in_array' => true, - 'array_indentation' => true, - - // Binary Operators - 'binary_operator_spaces' => [ - 'default' => 'single_space', - 'operators' => ['=>' => 'align_single_space_minimal'], + 'trim_array_spaces' => true, + 'normalize_index_brace' => true, + 'trailing_comma_in_multiline' => [ + 'elements' => ['arrays', 'arguments', 'parameters'], ], - 'concat_space' => ['spacing' => 'one'], - // Blank Lines + // ==================================================================== + // BLANK LINES + // ==================================================================== 'blank_line_after_namespace' => true, 'blank_line_after_opening_tag' => true, 'blank_line_before_statement' => [ - 'statements' => ['return', 'try', 'throw', 'declare'], + 'statements' => ['return', 'throw', 'try'], ], + // 'blank_lines_before_namespace' => [ + // 'min_line_breaks' => 1, + // 'max_line_breaks' => 1, + // ], + 'no_blank_lines_after_class_opening' => true, 'no_extra_blank_lines' => [ - 'tokens' => [ - 'extra', - 'throw', - 'use', - 'curly_brace_block', - ], + 'tokens' => ['extra', 'throw', 'use'], ], - // Casing - 'constant_case' => ['case' => 'lower'], - 'lowercase_keywords' => true, - 'lowercase_static_reference' => true, - 'magic_constant_casing' => true, - 'magic_method_casing' => true, - 'native_function_casing' => true, - 'native_function_type_declaration_casing' => true, - - // Cast Notation + // ==================================================================== + // CASTS + // ==================================================================== 'cast_spaces' => ['space' => 'single'], 'lowercase_cast' => true, - 'modernize_types_casting' => true, - 'no_short_bool_cast' => true, + 'short_scalar_cast' => true, 'no_unset_cast' => true, - // Class Notation + // ==================================================================== + // CLASSES + // ==================================================================== 'class_attributes_separation' => [ 'elements' => [ 'const' => 'one', @@ -91,95 +103,38 @@ 'trait_import' => 'none', ], ], - 'class_definition' => [ - 'multi_line_extends_each_single_line' => true, - 'single_item_single_line' => true, - 'single_line' => true, - ], - 'final_class' => false, // Allow non-final classes for framework components - 'final_internal_class' => false, - 'no_blank_lines_after_class_opening' => true, + 'single_class_element_per_statement' => true, + 'modifier_keywords' => true, // Substitui visibility_required 'no_null_property_initialization' => true, - 'ordered_class_elements' => [ - 'order' => [ - 'use_trait', - 'constant_public', - 'constant_protected', - 'constant_private', - 'property_public', - 'property_protected', - 'property_private', - 'construct', - 'destruct', - 'magic', - 'phpunit', - 'method_public', - 'method_protected', - 'method_private', - ], - 'sort_algorithm' => 'none', - ], - 'ordered_interfaces' => ['order' => 'alpha'], - 'protected_to_private' => true, 'self_accessor' => true, - 'self_static_accessor' => true, - 'single_class_element_per_statement' => true, - 'visibility_required' => [ - 'elements' => ['const', 'method', 'property'], - ], - - // Comments - 'comment_to_phpdoc' => true, - 'multiline_comment_opening_closing' => true, - 'no_empty_comment' => true, - 'single_line_comment_style' => ['comment_types' => ['hash']], - // Control Structures - 'control_structure_braces' => true, - 'control_structure_continuation_position' => ['position' => 'same_line'], - 'elseif' => true, + // ==================================================================== + // CONTROL STRUCTURES + // ==================================================================== 'no_alternative_syntax' => true, 'no_superfluous_elseif' => true, - 'no_trailing_comma_in_singleline' => true, 'no_useless_else' => true, 'simplified_if_return' => true, - 'switch_case_semicolon_to_colon' => true, - 'switch_case_space' => true, - 'trailing_comma_in_multiline' => ['elements' => ['arrays', 'arguments', 'parameters']], - - // Doctrine Annotations - 'doctrine_annotation_array_assignment' => false, - 'doctrine_annotation_braces' => false, - 'doctrine_annotation_indentation' => false, - 'doctrine_annotation_spaces' => false, + 'yoda_style' => false, + 'elseif' => true, - // Function Notation + // ==================================================================== + // FUNCTIONS + // ==================================================================== 'function_declaration' => ['closure_function_spacing' => 'one'], - 'function_typehint_space' => true, - 'lambda_not_used_import' => true, + 'type_declaration_spaces' => true, // Substitui function_typehint_space 'method_argument_space' => [ 'on_multiline' => 'ensure_fully_multiline', - 'keep_multiple_spaces_after_comma' => false, - ], - 'native_function_invocation' => [ - 'include' => ['@compiler_optimized'], - 'scope' => 'namespaced', ], 'no_spaces_after_function_name' => true, - 'nullable_type_declaration_for_default_null_value' => true, 'return_type_declaration' => ['space_before' => 'none'], - 'single_line_throw' => true, - 'void_return' => false, + 'void_return' => true, + 'native_function_casing' => true, + 'native_type_declaration_casing' => true, // Substitui native_function_type_declaration_casing - // Import Statements - 'fully_qualified_strict_types' => true, - 'global_namespace_import' => [ - 'import_classes' => true, - 'import_constants' => true, - 'import_functions' => true, - ], - 'no_leading_import_slash' => true, - 'no_unneeded_import_alias' => true, + // ==================================================================== + // IMPORTS + // ==================================================================== 'no_unused_imports' => true, 'ordered_imports' => [ 'sort_algorithm' => 'alpha', @@ -187,121 +142,94 @@ ], 'single_import_per_statement' => true, 'single_line_after_imports' => true, + 'no_leading_import_slash' => true, + 'global_namespace_import' => [ + 'import_classes' => true, + 'import_constants' => true, + 'import_functions' => true, + ], + 'fully_qualified_strict_types' => true, - // Language Constructs - 'combine_consecutive_issets' => true, - 'combine_consecutive_unsets' => true, - 'declare_equal_normalize' => ['space' => 'none'], - 'dir_constant' => true, - 'explicit_indirect_variable' => true, - 'is_null' => true, - 'modernize_strpos' => true, - 'no_unset_on_property' => false, - - // Namespaces - 'blank_line_after_namespace' => true, - 'no_blank_lines_before_namespace' => false, - 'single_blank_line_before_namespace' => true, + // ==================================================================== + // NAMESPACES + // ==================================================================== + 'no_leading_namespace_whitespace' => false, - // Operators - 'increment_style' => ['style' => 'post'], - 'logical_operators' => true, - 'no_space_around_double_colon' => true, - 'not_operator_with_successor_space' => true, + // ==================================================================== + // OPERATORS + // ==================================================================== + 'binary_operator_spaces' => [ + 'default' => 'single_space', + ], + 'concat_space' => ['spacing' => 'one'], + 'unary_operator_spaces' => true, + 'ternary_operator_spaces' => true, + 'new_with_parentheses' => true, 'object_operator_without_whitespace' => true, - 'operator_linebreak' => ['only_booleans' => true], 'standardize_not_equals' => true, - 'ternary_operator_spaces' => true, - 'ternary_to_elvis_operator' => true, 'ternary_to_null_coalescing' => true, - 'unary_operator_spaces' => true, - // PHPDoc - Configured to preserve comprehensive documentation like KaririCode\Router - 'align_multiline_comment' => ['comment_type' => 'phpdocs_like'], - 'general_phpdoc_annotation_remove' => false, // Keep all annotations including @author - 'no_blank_lines_after_phpdoc' => true, - 'no_empty_phpdoc' => true, - 'no_superfluous_phpdoc_tags' => false, // Keep all PHPDoc tags including type hints - 'phpdoc_add_missing_param_annotation' => ['only_untyped' => false], - 'phpdoc_align' => [ - 'align' => 'vertical', - 'tags' => ['param', 'return', 'throws', 'type', 'var', 'method'], - ], - 'phpdoc_annotation_without_dot' => false, // Allow dots in descriptions - 'phpdoc_indent' => true, - 'phpdoc_inline_tag_normalizer' => true, - 'phpdoc_line_span' => [ - 'const' => 'multi', - 'property' => 'multi', - 'method' => 'multi', - ], - 'phpdoc_no_access' => false, // Keep @access tags if present - 'phpdoc_no_alias_tag' => true, - 'phpdoc_no_package' => false, // Keep @package tags - 'phpdoc_no_useless_inheritdoc' => false, // Keep @inheritDoc for clarity - 'phpdoc_order' => ['order' => ['param', 'throws', 'return']], - 'phpdoc_order_by_value' => ['annotations' => ['covers', 'dataProvider']], - 'phpdoc_return_self_reference' => true, + // ==================================================================== + // PHP TAGS + // ==================================================================== + 'full_opening_tag' => true, + 'no_closing_tag' => true, + + // ==================================================================== + // PHPDOC (SAFE RULES) + // ==================================================================== 'phpdoc_scalar' => true, - 'phpdoc_separation' => [ - 'groups' => [ - ['deprecated', 'link', 'see', 'since'], - ['author', 'copyright', 'license'], - ['category', 'package', 'subpackage'], - ['property', 'property-read', 'property-write'], - ['param', 'return'], - ], - ], 'phpdoc_single_line_var_spacing' => true, - 'phpdoc_summary' => true, - 'phpdoc_tag_casing' => ['tags' => ['inheritDoc']], - 'phpdoc_tag_type' => ['tags' => ['inheritDoc' => 'inline']], - 'phpdoc_to_comment' => false, // Keep @var, @see, etc as PHPDoc - 'phpdoc_trim' => true, - 'phpdoc_trim_consecutive_blank_line_separation' => true, 'phpdoc_types' => true, - 'phpdoc_types_order' => [ - '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' => false, - - // Semicolons - 'multiline_whitespace_before_semicolons' => ['strategy' => 'no_multi_line'], + // ==================================================================== + // SEMICOLONS + // ==================================================================== 'no_empty_statement' => true, 'no_singleline_whitespace_before_semicolons' => true, 'semicolon_after_instruction' => true, - 'space_after_semicolon' => ['remove_in_empty_for_expressions' => true], + 'space_after_semicolon' => [ + 'remove_in_empty_for_expressions' => true, + ], - // Strings - 'explicit_string_variable' => true, - 'heredoc_to_nowdoc' => true, - 'simple_to_complex_string_variable' => true, + // ==================================================================== + // STRINGS + // ==================================================================== 'single_quote' => true, - 'string_line_ending' => true, + 'simple_to_complex_string_variable' => true, - // Whitespace - 'compact_nullable_typehint' => true, - 'heredoc_indentation' => ['indentation' => 'start_plus_one'], - 'indentation_type' => true, - 'line_ending' => true, - 'method_chaining_indentation' => true, - 'no_spaces_around_offset' => true, - 'no_spaces_inside_parenthesis' => true, + // ==================================================================== + // WHITESPACE + // ==================================================================== 'no_trailing_whitespace' => true, - 'no_trailing_whitespace_in_comment' => true, 'no_whitespace_in_blank_line' => true, 'single_blank_line_at_eof' => true, 'statement_indentation' => true, - 'types_spaces' => ['space' => 'none'], + + // ==================================================================== + // STRICT TYPING & SAFETY + // ==================================================================== + 'declare_strict_types' => true, + 'strict_comparison' => true, + 'strict_param' => true, + + // ==================================================================== + // PHP 8.4+ FEATURES + // ==================================================================== + 'modernize_types_casting' => true, + 'no_alias_functions' => true, + 'no_mixed_echo_print' => ['use' => 'echo'], + + // ==================================================================== + // CODE CLEANUP + // ==================================================================== + 'no_unreachable_default_argument_value' => true, + 'no_useless_return' => true, + 'combine_consecutive_issets' => true, + 'combine_consecutive_unsets' => true, ]) ->setFinder($finder) - ->setLineEnding("\n") - ->setUsingCache(true) - ->setCacheFile(__DIR__ . '/.php-cs-fixer.cache'); + ->setCacheFile(__DIR__ . '/.php-cs-fixer.cache') + ->setIndent(' ') + ->setLineEnding("\n"); diff --git a/.vscode/README.md b/.vscode/README.md new file mode 100644 index 0000000..c243ced --- /dev/null +++ b/.vscode/README.md @@ -0,0 +1,409 @@ +# VS Code Configuration - KaririCode\Parser + +Professional VS Code workspace configuration for KaririCode\Parser development, integrating all quality tools and preserving premium documentation standards. + +## 📁 Files Overview + +``` +.vscode/ +├── settings.json # Workspace settings (tools integration) +├── extensions.json # Recommended extensions +├── tasks.json # Makefile integration +├── launch.json # Debug configurations +├── php.code-snippets # Documentation snippets +└── README.md # This file +``` + +## 🚀 Quick Start + +### 1. Install Required Tools + +First, ensure your system has PHP 8.4+ and Composer: + +```bash +php -v # Should show 8.4+ +composer --version +``` + +### 2. Install Project Dependencies + +```bash +make install +# or manually: +composer install +``` + +### 3. Install VS Code Extensions + +Open VS Code and press `Ctrl+Shift+P` (or `Cmd+Shift+P` on macOS), then: + +1. Type: `Extensions: Show Recommended Extensions` +2. Click "Install All" or install individually: + - **Essential**: Intelephense, PHP-CS-Fixer, PHPStan, Psalm + - **Highly Recommended**: Better Comments, Error Lens, Todo Tree + - **Optional**: See `extensions.json` for full list + +### 4. Configure XDebug (Optional) + +For debugging, install and configure XDebug 3.x: + +```bash +# Ubuntu/Debian +sudo apt-get install php8.4-xdebug + +# macOS (Homebrew) +brew install php@8.4-xdebug +``` + +Add to `php.ini` (find with `php --ini`): + +```ini +[XDebug] +zend_extension=xdebug.so +xdebug.mode=debug,coverage +xdebug.start_with_request=yes +xdebug.client_port=9003 +xdebug.client_host=127.0.0.1 +xdebug.idekey=VSCODE +``` + +Restart PHP and verify: + +```bash +php -v # Should show "with Xdebug" +``` + +## 🛠️ Tool Integration + +### PHP-CS-Fixer + +**What it does**: Formats PHP code according to PSR-12 and custom rules while **preserving premium comments**. + +**How to use**: +- Via Command Palette: `Format Document` (when PHP file is active) +- Via Task: `Ctrl+Shift+B` → "Format Code (PHP-CS-Fixer)" +- Via Makefile: `make format` +- Via Terminal: `vendor/bin/php-cs-fixer fix` + +**Important**: Auto-format on save is **disabled** to preserve premium documentation. Format manually when needed. + +### PHPStan + +**What it does**: Static analysis at maximum strictness level. + +**How to use**: +- Automatic: Errors appear in "Problems" panel as you type +- Via Task: `Ctrl+Shift+B` → "Run PHPStan" +- Via Makefile: `make phpstan` +- Via Terminal: `vendor/bin/phpstan analyse` + +**Configuration**: `phpstan.neon` (level: max) + +### Psalm + +**What it does**: Additional static analysis with different heuristics. + +**How to use**: +- Automatic: Errors appear alongside PHPStan +- Via Task: `Ctrl+Shift+B` → "Run Psalm" +- Via Makefile: `make psalm` +- Via Terminal: `vendor/bin/psalm` + +**Configuration**: `psalm.xml` (errorLevel: 1) + +### PHPCS (PHP_CodeSniffer) + +**What it does**: Checks PSR-12 compliance with custom rules. + +**How to use**: +- Automatic: Warnings appear in "Problems" panel +- Via Task: "Check Coding Standards" +- Via Makefile: `make cs-check` +- Auto-fix: `make cs-fix` + +**Configuration**: `phpcs.xml` + +### PHPUnit + +**What it does**: Runs test suites. + +**How to use**: +- Via Test Explorer (sidebar icon) +- Via Task: `Ctrl+Shift+B` → "Run All Tests" +- Via Debug: `F5` → Select "PHPUnit: Debug..." +- Via Makefile: `make test` + +**Configuration**: `phpunit.xml` + +## ⌨️ Keyboard Shortcuts + +### Essential Commands + +| Shortcut | Action | +|----------|--------| +| `Ctrl+Shift+B` | Open Build Tasks menu | +| `F5` | Start debugging | +| `Shift+F5` | Stop debugging | +| `F9` | Toggle breakpoint | +| `F10` | Step over | +| `F11` | Step into | +| `Shift+F11` | Step out | +| `Ctrl+Shift+P` | Command Palette | +| `Ctrl+P` | Quick Open File | +| `Ctrl+Shift+F` | Search in Files | + +### Custom Tasks (via `Ctrl+Shift+B`) + +**Testing**: +- Run All Tests +- Run Unit Tests +- Run Integration Tests +- Generate Coverage Report +- Run Mutation Tests + +**Analysis**: +- Run All Analysis +- Run PHPStan +- Run Psalm +- Check Coding Standards + +**Formatting**: +- Format Code (PHP-CS-Fixer) +- Fix Coding Standards +- Lint PHP Files + +**Quality**: +- Run All Quality Checks +- Run CI Pipeline +- Run Full CI Pipeline +- Run Pre-Commit Checks + +**Docker**: +- Docker: Run Tests +- Docker: Run CI +- Docker: Open Shell + +## 🐛 Debugging Guide + +### Debug Current Test File + +1. Open test file (e.g., `tests/Unit/SomeTest.php`) +2. Press `F5` +3. Select "PHPUnit: Debug Current Test File" +4. Set breakpoints with `F9` + +### Debug Specific Test Method + +1. Select test method name +2. Press `F5` +3. Select "PHPUnit: Debug Current Test Method" + +### Debug PHP Script + +1. Open PHP file +2. Press `F5` +3. Select "Launch Currently Open Script" + +### Listen for XDebug (Browser/CLI) + +1. Press `F5` +2. Select "Listen for XDebug" +3. Trigger PHP execution with `XDEBUG_TRIGGER=1` + +Example: +```bash +XDEBUG_MODE=debug XDEBUG_TRIGGER=1 php script.php +``` + +## 📝 Code Snippets + +Type these prefixes and press `Tab`: + +### Documentation + +| Prefix | Description | +|--------|-------------| +| `kc-class-doc` | Premium class documentation (800-1200 lines) | +| `kc-method-doc` | Method documentation with examples | +| `kc-doc` | Simple PHPDoc block | +| `kc-prop-doc` | Property documentation | +| `kc-perf` | Performance annotation | +| `kc-algo` | Algorithm documentation | + +### Templates + +| Prefix | Description | +|--------|-------------| +| `kc-class` | Class template | +| `kc-interface` | Interface template | +| `kc-trait` | Trait template | +| `kc-enum` | Enum template | +| `kc-exception` | Exception class | +| `kc-test` | Test class template | +| `kc-test-method` | Test method | + +### Common Patterns + +| Prefix | Description | +|--------|-------------| +| `kc-construct` | Constructor with promoted properties | +| `kc-get` | Getter method | + +Example usage: + +```php +// Type 'kc-class-doc' and press Tab +/** + * Brief description of the class + * + * Detailed description... + * [Full premium documentation template] + */ +``` + +## 🔧 Troubleshooting + +### Extensions Not Working + +1. Reload VS Code: `Ctrl+Shift+P` → "Developer: Reload Window" +2. Check extension status: `Ctrl+Shift+X` +3. Verify paths in `settings.json`: + ```json + "phpstan.path": "${workspaceFolder}/vendor/bin/phpstan" + ``` +4. Ensure Composer dependencies installed: `make install` + +### XDebug Not Connecting + +1. Verify XDebug installed: + ```bash + php -m | grep xdebug + ``` +2. Check XDebug configuration: + ```bash + php -i | grep xdebug + ``` +3. Verify port 9003 is not in use: + ```bash + netstat -an | grep 9003 + ``` +4. Check `launch.json` port matches `php.ini`: + ```json + "port": 9003 + ``` + +### PHPStan/Psalm Errors Not Showing + +1. Open "Output" panel (`Ctrl+Shift+U`) +2. Select "PHPStan" or "Psalm" from dropdown +3. Check for error messages +4. Verify cache directory writable: + ```bash + mkdir -p var/cache/{phpstan,psalm} + chmod 755 var/cache/{phpstan,psalm} + ``` + +### Format Not Working + +1. Ensure PHP-CS-Fixer installed: + ```bash + test -f vendor/bin/php-cs-fixer && echo "OK" + ``` +2. Check `.php-cs-fixer.php` exists +3. Run manually to see errors: + ```bash + make format + ``` +4. Verify VS Code setting: + ```json + "[php]": { + "editor.defaultFormatter": "junstyle.php-cs-fixer" + } + ``` + +### Tests Not Found in Test Explorer + +1. Reload tests: Click refresh icon in Test Explorer +2. Verify PHPUnit config: + ```bash + vendor/bin/phpunit --list-tests + ``` +3. Check `phpunit.xml` is valid XML +4. Restart PHP Language Server: + `Ctrl+Shift+P` → "PHP: Restart Language Server" + +## 📚 Additional Resources + +### Documentation +- [PHP-CS-Fixer Rules](https://cs.symfony.com/) +- [PHPStan Levels](https://phpstan.org/user-guide/rule-levels) +- [Psalm Error Levels](https://psalm.dev/docs/running_psalm/error_levels/) +- [PHPUnit Documentation](https://phpunit.de/documentation.html) +- [XDebug Documentation](https://xdebug.org/docs/) + +### KaririCode Standards +- [COMMENTING_GUIDELINES.md](../COMMENTING_GUIDELINES.md) - Premium documentation philosophy +- [Makefile](../Makefile) - Development workflow automation +- [composer.json](../composer.json) - Dependencies and scripts + +### VS Code +- [PHP Development](https://code.visualstudio.com/docs/languages/php) +- [Debugging](https://code.visualstudio.com/docs/editor/debugging) +- [Tasks](https://code.visualstudio.com/docs/editor/tasks) + +## 🔐 Security Note + +**Never commit**: +- `.vscode/*.log` - Debug logs +- `.vscode/settings.local.json` - Personal overrides +- XDebug profiler output + +These are already in `.gitignore`. + +## 🎯 Pro Tips + +1. **Split View Testing**: Open test and source side-by-side with `Ctrl+\` + +2. **Quick Test Run**: Use Makefile shortcuts + ```bash + make test-unit # Fast unit tests + make coverage # Generate coverage + make mutation # Mutation testing + ``` + +3. **Multi-cursor Editing**: `Alt+Click` to add cursors, great for batch PHPDoc updates + +4. **Search in Tests Only**: + - Press `Ctrl+Shift+F` + - Click "..." → "files to include" + - Enter: `tests/**/*.php` + +5. **Format Only Specific File**: + ```bash + vendor/bin/php-cs-fixer fix src/Specific/File.php + ``` + +6. **Quick CI Check Before Commit**: + ```bash + make pre-commit + ``` + +7. **Docker Isolation**: Use Docker tasks for CI/CD consistency + ```bash + make docker-ci + ``` + +8. **Zen Mode**: `Ctrl+K Z` for distraction-free coding + +## 🆘 Support + +Issues with VS Code configuration? Check: +1. This README first +2. [COMMENTING_GUIDELINES.md](../COMMENTING_GUIDELINES.md) +3. Project issues: https://github.com/KaririCode-Framework/kariricode-parser/issues + +--- + +**Last Updated**: 2025-01-27 +**Version**: 1.0.0 +**Maintainer**: Walmir Silva diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..160050e --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,171 @@ +{ + // ============================================================================ + // KaririCode\Parser - Recommended VS Code Extensions + // ============================================================================ + // Essential and recommended extensions for PHP 8.4+ development with + // KaririCode quality standards + // + // Last Updated: 2025-01-27 + // Validated against: VS Code marketplace latest releases + // ============================================================================ + + "recommendations": [ + // ===== ESSENTIAL EXTENSIONS ===== + // These extensions are critical for KaririCode development workflow + + // PHP Language Server - Primary IntelliSense + // Provides fast code completion, go to definition, workspace symbols + // Zero dependencies, highly performant + "bmewburn.vscode-intelephense-client", + + // PHP-CS-Fixer Integration + // Auto-formats PHP code according to PSR-12 and custom rules + // CRITICAL: Preserves premium documentation comments (800-1200 lines) + "junstyle.php-cs-fixer", + + // PHPStan Static Analysis + // Static analyzer at maximum strictness level (level: max) + // Detects bugs and type errors before runtime + "swordev.phpstan", + + // Psalm Static Analysis + // Additional static analysis with different heuristics + // Complements PHPStan for comprehensive type checking + "getpsalm.psalm-vscode-plugin", + + // PHP Sniffer & Beautifier + // Integrates phpcs (linting) + phpcbf (auto-fix) + // Best PHPCS extension validated by Drupal community (2025) + // Multi-root workspace support, works out-of-the-box + "ValeryanM.vscode-phpsab", + + // PHPUnit Test Runner + // Runs tests directly from VS Code with Test Explorer integration + // Supports debugging individual tests + "recca0120.vscode-phpunit", + + // PHP Debug + // XDebug 3.x integration for debugging and profiling + // Essential for development and troubleshooting + "xdebug.php-debug", + + // EditorConfig Support + // Maintains consistent coding styles between editors + // Automatically applies .editorconfig rules + "editorconfig.editorconfig", + + // ===== HIGHLY RECOMMENDED ===== + // Strongly recommended for productivity and code quality + + // Better Comments + // Enhances comment visibility with color coding + // Perfect for premium documentation with TODO, FIXME, NOTE tags + "aaron-bond.better-comments", + + // Error Lens + // Displays errors and warnings inline + // Improves error visibility and debugging speed + "usernamehw.errorlens", + + // Todo Tree + // Aggregates TODO, FIXME, BUG, OPTIMIZE comments + // Searchable tree view for task tracking + "gruntfuggly.todo-tree", + + // GitLens + // Advanced Git integration and history visualization + // Blame annotations, commit search, powerful comparisons + "eamodio.gitlens", + + // Git Graph + // Visual Git commit history graph + // Complements GitLens for repository visualization + "mhutchie.git-graph", + + // PHP Namespace Resolver + // Auto-imports and resolves PHP namespaces + // Saves time on use statements + "mehedidracula.php-namespace-resolver", + + // ===== OPTIONAL BUT USEFUL ===== + // Enhance specific workflows when needed + + // Docker Integration + // Manage containers, images, and compose files + // Essential if using Docker for development + "ms-azuretools.vscode-docker", + + // YAML Support + // Syntax highlighting and validation for YAML files + // Used in phpstan.neon, docker-compose.yml, CI/CD configs + "redhat.vscode-yaml", + + // XML Tools + // XML formatting, validation, and XPath evaluation + // Used in phpunit.xml, phpcs.xml, psalm.xml + "redhat.vscode-xml", + + // Markdown All in One + // Enhanced Markdown editing with preview and shortcuts + // Useful for README.md and documentation files + "yzhang.markdown-all-in-one", + + // REST Client + // Test HTTP requests directly from .http files + // Alternative to Postman for API testing + "humao.rest-client", + + // Makefile Tools + // Syntax highlighting and IntelliSense for Makefiles + // KaririCode uses Makefile for automation + "ms-vscode.makefile-tools", + + // DotENV Syntax + // Syntax highlighting for .env files + // Common in PHP projects for configuration + "mikestead.dotenv", + + // PHP DocBlocker + // Assists with PHPDoc generation (optional) + // KaririCode primarily uses custom snippets, but can help + "neilbrayfield.php-docblocker" + + // ===== AI CODING ASSISTANTS (OPTIONAL) ===== + // Uncomment ONE of these if desired: + // "github.copilot", // GitHub Copilot (paid, most popular) + // "codeium.codeium", // Codeium (free alternative) + // "continue.continue" // Continue (open-source, local LLMs) + ], + + // ===== NOT RECOMMENDED ===== + // Extensions that conflict with quality standards or are deprecated + "unwantedRecommendations": [ + // ===== FORMATTING CONFLICTS ===== + // These interfere with PHP-CS-Fixer configuration + "esbenp.prettier-vscode", + "hookyqr.beautify", + + // ===== INTELLISENSE CONFLICTS ===== + // These conflict with Intelephense or provide duplicate functionality + "vscode.php-language-features", + "zobo.php-intellisense", + "ikappas.composer", + + // ===== DEPRECATED/ABANDONED ===== + // These extensions are no longer maintained or have better alternatives + "coenraads.bracket-pair-colorizer-2", + "calebporzio.better-phpunit", + "phproberto.vscode-php-getters-setters", + "christian-kohler.path-intellisense", + + // ===== PHPCS ALTERNATIVES (INFERIOR) ===== + // Validated by Drupal.org (August 2025) as problematic + "ikappas.phpcs", + "shevaua.phpcs", + "obliviousharmony.vscode-php-codesniffer", + + // ===== LOWER QUALITY TOOLS ===== + "dotjoshjohnson.xml", + "streetsidesoftware.code-spell-checker" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..cbd3a07 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,175 @@ +{ + // ============================================================================ + // KaririCode\Parser - VS Code Debug Configurations + // ============================================================================ + // XDebug 3.x configurations for debugging PHP code and tests + // ============================================================================ + + "version": "0.2.0", + "configurations": [ + // ===== XDEBUG - LISTEN FOR CONNECTIONS ===== + { + "name": "Listen for XDebug", + "type": "php", + "request": "launch", + "port": 9003, + "log": true, + "pathMappings": { + "/app": "${workspaceFolder}" + }, + "xdebugSettings": { + "max_data": 65535, + "show_hidden": 1, + "max_children": 100, + "max_depth": 5 + } + }, + + // ===== XDEBUG - LAUNCH CURRENT FILE ===== + { + "name": "Launch Currently Open Script", + "type": "php", + "request": "launch", + "program": "${file}", + "cwd": "${fileDirname}", + "port": 9003, + "runtimeArgs": ["-dxdebug.mode=debug", "-dxdebug.start_with_request=yes"], + "env": { + "XDEBUG_MODE": "debug", + "XDEBUG_CONFIG": "client_port=9003" + } + }, + + // ===== PHPUNIT - DEBUG CURRENT TEST FILE ===== + { + "name": "PHPUnit: Debug Current Test File", + "type": "php", + "request": "launch", + "program": "${workspaceFolder}/vendor/bin/phpunit", + "args": ["${file}", "--colors=always", "--testdox"], + "cwd": "${workspaceFolder}", + "port": 9003, + "runtimeArgs": ["-dxdebug.mode=debug", "-dxdebug.start_with_request=yes"], + "env": { + "XDEBUG_MODE": "debug,coverage" + } + }, + + // ===== PHPUNIT - DEBUG SPECIFIC TEST METHOD ===== + { + "name": "PHPUnit: Debug Current Test Method", + "type": "php", + "request": "launch", + "program": "${workspaceFolder}/vendor/bin/phpunit", + "args": [ + "${file}", + "--filter", + "${selectedText}", + "--colors=always", + "--testdox" + ], + "cwd": "${workspaceFolder}", + "port": 9003, + "runtimeArgs": ["-dxdebug.mode=debug", "-dxdebug.start_with_request=yes"], + "env": { + "XDEBUG_MODE": "debug" + } + }, + + // ===== PHPUNIT - DEBUG ALL UNIT TESTS ===== + { + "name": "PHPUnit: Debug All Unit Tests", + "type": "php", + "request": "launch", + "program": "${workspaceFolder}/vendor/bin/phpunit", + "args": ["--testsuite=Unit", "--colors=always", "--testdox"], + "cwd": "${workspaceFolder}", + "port": 9003, + "runtimeArgs": ["-dxdebug.mode=debug", "-dxdebug.start_with_request=yes"], + "env": { + "XDEBUG_MODE": "debug" + } + }, + + // ===== PHPUNIT - DEBUG ALL INTEGRATION TESTS ===== + { + "name": "PHPUnit: Debug Integration Tests", + "type": "php", + "request": "launch", + "program": "${workspaceFolder}/vendor/bin/phpunit", + "args": ["--testsuite=Integration", "--colors=always", "--testdox"], + "cwd": "${workspaceFolder}", + "port": 9003, + "runtimeArgs": ["-dxdebug.mode=debug", "-dxdebug.start_with_request=yes"], + "env": { + "XDEBUG_MODE": "debug" + } + }, + + // ===== PHPUNIT - DEBUG ALL TESTS ===== + { + "name": "PHPUnit: Debug All Tests", + "type": "php", + "request": "launch", + "program": "${workspaceFolder}/vendor/bin/phpunit", + "args": ["--colors=always", "--testdox"], + "cwd": "${workspaceFolder}", + "port": 9003, + "runtimeArgs": ["-dxdebug.mode=debug", "-dxdebug.start_with_request=yes"], + "env": { + "XDEBUG_MODE": "debug" + } + }, + + // ===== PHPSTAN - DEBUG ANALYSIS ===== + { + "name": "PHPStan: Debug Analysis", + "type": "php", + "request": "launch", + "program": "${workspaceFolder}/vendor/bin/phpstan", + "args": ["analyse", "src", "--level=max", "--memory-limit=512M"], + "cwd": "${workspaceFolder}", + "port": 9003, + "runtimeArgs": ["-dxdebug.mode=debug", "-dxdebug.start_with_request=yes"] + }, + + // ===== PSALM - DEBUG ANALYSIS ===== + { + "name": "Psalm: Debug Analysis", + "type": "php", + "request": "launch", + "program": "${workspaceFolder}/vendor/bin/psalm", + "args": ["--show-info=true", "--stats"], + "cwd": "${workspaceFolder}", + "port": 9003, + "runtimeArgs": ["-dxdebug.mode=debug", "-dxdebug.start_with_request=yes"] + }, + + // ===== COMPOSER - DEBUG OPERATIONS ===== + { + "name": "Composer: Debug Install", + "type": "php", + "request": "launch", + "program": "/usr/bin/composer", + "args": ["install", "--no-interaction", "-vvv"], + "cwd": "${workspaceFolder}", + "port": 9003, + "runtimeArgs": ["-dxdebug.mode=debug", "-dxdebug.start_with_request=yes"] + }, + + // ===== BENCHMARK - DEBUG PERFORMANCE ===== + { + "name": "PHPBench: Debug Benchmarks", + "type": "php", + "request": "launch", + "program": "${workspaceFolder}/vendor/bin/phpbench", + "args": ["run", "--report=default"], + "cwd": "${workspaceFolder}", + "port": 9003, + "runtimeArgs": ["-dxdebug.mode=debug", "-dxdebug.start_with_request=yes"], + "env": { + "XDEBUG_MODE": "debug" + } + } + ] +} diff --git a/.vscode/php.code-snippets b/.vscode/php.code-snippets new file mode 100644 index 0000000..45d9915 --- /dev/null +++ b/.vscode/php.code-snippets @@ -0,0 +1,405 @@ +{ + // ============================================================================ + // KaririCode\Parser - PHP Code Snippets + // ============================================================================ + // Premium documentation snippets following KaririCode standards + // Usage: Type snippet prefix and press Tab + // ============================================================================ + + // ===== CLASS DOCUMENTATION ===== + + "KaririCode Class Documentation": { + "prefix": "kc-class-doc", + "body": [ + "/**", + " * ${1:Brief description of the class}", + " *", + " * ${2:Detailed description explaining:", + " * - What it does", + " * - Why it exists", + " * - How it fits into the ecosystem", + " * - Key design decisions}", + " *", + " * ## ${3:Feature Name} Specification", + " *", + " * ${4:Specification details}", + " *", + " * ## Supported Patterns", + " *", + " * ### 1. ${5:Pattern Name}", + " * ```php", + " * ${6:// Example code}", + " * ```", + " *", + " * ## Performance Characteristics", + " *", + " * - **Parse Speed**: ${7:~XXXns per operation}", + " * - **Memory**: ${8:O(n) where n = ...}", + " * - **Throughput**: ${9:XXX ops/sec}", + " *", + " * ## Algorithm Details", + " *", + " * **Phase 1: ${10:Name}**", + " * 1. ${11:Step description}", + " *", + " * ## Error Handling", + " *", + " * Throws ${12:ExceptionType} for:", + " * - ${13:Condition 1}", + " * - ${14:Condition 2}", + " *", + " * ## Limitations", + " *", + " * - ${15:Limitation 1}", + " * - ${16:Limitation 2}", + " *", + " * ## References", + " *", + " * - ${17:Reference with link}", + " *", + " * @package KaririCode\\\\Parser\\\\${18:Namespace}", + " * @author Walmir Silva ", + " * @see ${19:RelatedClass} For ${20:context}", + " * @link ${21:https://wiki.php.net/rfc/...}", + " * @since ${22:1.0.0}", + " */" + ], + "description": "KaririCode premium class documentation template" + }, + + "KaririCode Method Documentation": { + "prefix": "kc-method-doc", + "body": [ + "/**", + " * ${1:Brief description of what method does}", + " *", + " * ${2:Optional detailed explanation if method is complex}", + " *", + " * **Example 1: ${3:Use Case Name}**", + " * ```php", + " * ${4:// Example code}", + " * // ${5:Expected output/behavior}", + " * ```", + " *", + " * **Example 2: ${6:Another Use Case}**", + " * ```php", + " * ${7:// Example code}", + " * // ${8:Expected output/behavior}", + " * ```", + " *", + " * **Performance**: ${9:~XXXns per operation}", + " *", + " * @param ${10:Type} \\$${11:param} ${12:Description}", + " * @param ${13:Type} \\$${14:param2} ${15:Description}", + " *", + " * @return ${16:ReturnType} ${17:Description}", + " *", + " * @throws ${18:ExceptionType} If ${19:condition}", + " *", + " * @see ${20:RelatedMethod} For ${21:related functionality}", + " */" + ], + "description": "KaririCode method documentation with examples" + }, + + // ===== QUICK DOCUMENTATION ===== + + "Simple PHPDoc Block": { + "prefix": "kc-doc", + "body": [ + "/**", + " * ${1:Description}", + " *", + " * @param ${2:Type} \\$${3:param} ${4:Description}", + " *", + " * @return ${5:Type} ${6:Description}", + " */" + ], + "description": "Simple PHPDoc block" + }, + + "Property Documentation": { + "prefix": "kc-prop-doc", + "body": [ + "/**", + " * ${1:Description}", + " *", + " * @var ${2:Type}", + " */" + ], + "description": "Property documentation" + }, + + // ===== CLASS TEMPLATES ===== + + "KaririCode Class Template": { + "prefix": "kc-class", + "body": [ + "", + " * @since ${4:1.0.0}", + " */", + "final class ${5:ClassName}", + "{", + " ${0}", + "}" + ], + "description": "KaririCode class template" + }, + + "KaririCode Interface Template": { + "prefix": "kc-interface", + "body": [ + "", + " * @since ${4:1.0.0}", + " */", + "interface ${5:InterfaceName}", + "{", + " ${0}", + "}" + ], + "description": "KaririCode interface template" + }, + + "KaririCode Trait Template": { + "prefix": "kc-trait", + "body": [ + "", + " * @since ${4:1.0.0}", + " */", + "trait ${5:TraitName}", + "{", + " ${0}", + "}" + ], + "description": "KaririCode trait template" + }, + + "KaririCode Enum Template": { + "prefix": "kc-enum", + "body": [ + "", + " * @since ${4:1.0.0}", + " */", + "enum ${5:EnumName}: ${6:string}", + "{", + " case ${7:CASE_NAME} = '${8:value}';", + " ${0}", + "}" + ], + "description": "KaririCode enum template" + }, + + // ===== TEST TEMPLATES ===== + + "KaririCode Test Class": { + "prefix": "kc-test", + "body": [ + "${3:instance} = new ${2:ClassName}();", + " }", + "", + " public function test${4:MethodName}(): void", + " {", + " // Arrange", + " ${5:// Setup}", + "", + " // Act", + " ${6:\\$result = \\$this->${3:instance}->${7:method}();}", + "", + " // Assert", + " ${8:\\$this->assertSame(\\$expected, \\$result);}", + " }", + " ${0}", + "}" + ], + "description": "KaririCode test class template" + }, + + "Test Method": { + "prefix": "kc-test-method", + "body": [ + "public function test${1:MethodName}(): void", + "{", + " // Arrange", + " ${2:// Setup}", + "", + " // Act", + " ${3:\\$result = \\$this->instance->${4:method}();}", + "", + " // Assert", + " ${5:\\$this->assertSame(\\$expected, \\$result);}", + "}" + ], + "description": "Test method template" + }, + + // ===== PERFORMANCE ANNOTATIONS ===== + + "Performance Note": { + "prefix": "kc-perf", + "body": [ + "/**", + " * Performance: ~${1:XXX}${2|ns,μs,ms|} per ${3:operation}", + " *", + " * Measured on:", + " * - PHP ${4:8.4.0}", + " * - ${5:CPU info}", + " * - ${6:RAM info}", + " *", + " * Benchmarked using PHPBench with ${7:1000} iterations.", + " */" + ], + "description": "Performance documentation" + }, + + "Algorithm Documentation": { + "prefix": "kc-algo", + "body": [ + "/**", + " * ## Algorithm Details", + " *", + " * **Phase 1: ${1:Name}**", + " * 1. ${2:Step description}", + " * 2. ${3:Step description}", + " *", + " * **Phase 2: ${4:Name}**", + " * 1. ${5:Step description}", + " * 2. ${6:Step description}", + " *", + " * **Complexity**: ${7:O(n)}", + " * **Space**: ${8:O(1)}", + " */" + ], + "description": "Algorithm documentation" + }, + + // ===== COMMON PATTERNS ===== + + "Constructor with Promoted Properties": { + "prefix": "kc-construct", + "body": [ + "/**", + " * ${1:Description}", + " *", + " * @param ${2:Type} \\$${3:property} ${4:Description}", + " */", + "public function __construct(", + " private readonly ${2:Type} \\$${3:property},", + ") {", + " ${0}", + "}" + ], + "description": "Constructor with promoted properties" + }, + + "Getter Method": { + "prefix": "kc-get", + "body": [ + "/**", + " * ${1:Description}", + " *", + " * @return ${2:Type}", + " */", + "public function get${3:Property}(): ${2:Type}", + "{", + " return \\$this->${4:property};", + "}" + ], + "description": "Getter method" + }, + + // ===== EXCEPTION TEMPLATES ===== + + "KaririCode Exception": { + "prefix": "kc-exception", + "body": [ + "", + " * @since ${3:1.0.0}", + " */", + "final class ${4:ExceptionName} extends RuntimeException", + "{", + " ${0}", + "}" + ], + "description": "KaririCode exception class" + } +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..062a45d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,155 @@ +{ + // ============================================================================ + // KaririCode\Parser - VS Code Workspace Settings + // ============================================================================ + // Professional workspace configuration with AUTO-FORMAT ON SAVE enabled + // Last Updated: 2025-01-27 + // ============================================================================ + + // ===== PHP CONFIGURATION ===== + "php.suggest.basic": false, + "php.validate.enable": true, + "php.validate.executablePath": "/usr/bin/php", + "php.validate.run": "onType", + + // ===== INTELEPHENSE ===== + "intelephense.stubs": [ + "Core", "date", "standard", "pcre", "SPL", "Reflection", + "apache", "bcmath", "bz2", "calendar", "ctype", "curl", "dba", "dom", + "enchant", "exif", "FFI", "fileinfo", "filter", "ftp", "gd", "gettext", + "gmp", "hash", "iconv", "imap", "intl", "json", "ldap", "libxml", + "mbstring", "mysqli", "oci8", "openssl", "pcntl", "PDO", "pdo_mysql", + "pdo_pgsql", "pdo_sqlite", "Phar", "posix", "pspell", "random", + "readline", "session", "shmop", "SimpleXML", "soap", "sockets", + "sodium", "sqlite3", "sysvmsg", "sysvsem", "sysvshm", "tokenizer", + "xml", "xmlreader", "xmlwriter", "xsl", "Zend OPcache", "zip", "zlib" + ], + "intelephense.diagnostics.enable": true, + "intelephense.diagnostics.run": "onType", + "intelephense.diagnostics.undefinedTypes": true, + "intelephense.diagnostics.undefinedFunctions": true, + "intelephense.diagnostics.undefinedConstants": true, + "intelephense.diagnostics.undefinedMethods": true, + "intelephense.diagnostics.undefinedProperties": true, + "intelephense.diagnostics.undefinedVariables": true, + "intelephense.diagnostics.unusedSymbols": true, + "intelephense.completion.maxItems": 100, + "intelephense.format.enable": false, + "intelephense.telemetry.enabled": false, + + // ===== PHP-CS-FIXER (AUTO-FORMAT ENABLED) ===== + "php-cs-fixer.executablePath": "${workspaceFolder}/vendor/bin/php-cs-fixer", + "php-cs-fixer.onsave": true, // ← HABILITADO + "php-cs-fixer.config": "${workspaceFolder}/.php-cs-fixer.php", + "php-cs-fixer.allowRisky": true, + "php-cs-fixer.pathMode": "override", + "php-cs-fixer.exclude": ["vendor"], + "php-cs-fixer.documentFormattingProvider": true, + + // ===== PHPSTAN ===== + "phpstan.enabled": true, + "phpstan.level": "max", + "phpstan.enableStatusBar": true, + "phpstan.enableLanguageServer": true, + "phpstan.path": "${workspaceFolder}/vendor/bin/phpstan", + "phpstan.configFile": "${workspaceFolder}/phpstan.neon", + "phpstan.memoryLimit": "512M", + "phpstan.options": ["--no-progress"], + + // ===== PSALM ===== + "psalm.enabled": true, + "psalm.path": "${workspaceFolder}/vendor/bin/psalm", + "psalm.configPaths": ["${workspaceFolder}/psalm.xml"], + "psalm.unusedVariableDetection": true, + + // ===== PHPCS (ValeryanM.vscode-phpsab) ===== + "phpsab.snifferEnable": true, + "phpsab.fixerEnable": false, + "phpsab.executablePathCS": "${workspaceFolder}/vendor/bin/phpcs", + "phpsab.standard": "Automatic", + "phpsab.autoRulesetSearch": true, + "phpsab.snifferMode": "onSave", + "phpsab.snifferShowSources": true, + + // ===== PHPUNIT ===== + "phpunit.php": "/usr/bin/php", + "phpunit.phpunit": "${workspaceFolder}/vendor/bin/phpunit", + "phpunit.args": ["--colors=always", "--testdox"], + "phpunit.clearOutputOnRun": true, + "phpunit.showAfterExecution": "always", + + // ==== DOCS ===== + "xml.fileAssociations": [ + { + "systemId": "https://raw.githubusercontent.com/phpDocumentor/phpDocumentor/master/data/xsd/phpdoc.xsd", // The schema URL from the docs + "pattern": "**/phpdoc.dist.xml" // Apply this schema to these files + } + ], + + // ===== EDITOR - GENERAL ===== + "editor.formatOnSave": true, // ← HABILITADO GLOBALMENTE + "editor.formatOnPaste": false, + "editor.formatOnType": false, + "editor.tabSize": 4, + "editor.insertSpaces": true, + "editor.detectIndentation": false, + "editor.trimAutoWhitespace": false, + "editor.rulers": [80, 120], + "editor.wordWrap": "off", + "editor.renderWhitespace": "boundary", + "editor.bracketPairColorization.enabled": true, + "editor.guides.bracketPairs": true, + "editor.minimap.enabled": true, + + // ===== EDITOR - PHP SPECIFIC ===== + "[php]": { + "editor.defaultFormatter": "junstyle.php-cs-fixer", // ← USAR PHP-CS-FIXER + "editor.formatOnSave": true, // ← HABILITADO PARA PHP + "editor.tabSize": 4, + "editor.insertSpaces": true, + "editor.rulers": [80, 120, 180], + "editor.codeActionsOnSave": { + "source.organizeImports": "never", + "source.fixAll": "never" + } + }, + + // ===== FILES ===== + "files.encoding": "utf8", + "files.eol": "\n", + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "files.trimTrailingWhitespace": false, + "files.autoSave": "onFocusChange", + "files.associations": { + "*.php": "php", + "*.neon": "yaml", + ".php-cs-fixer.php": "php", + "phpstan.neon": "yaml", + "psalm.xml": "xml", + "phpunit.xml": "xml", + "phpcs.xml": "xml" + }, + "files.exclude": { + "**/.git": true, + "**/.DS_Store": true, + "**/vendor": false, + "**/.phpunit.cache": true, + "**/.php-cs-fixer.cache": true + }, + + // ===== TODO TREE ===== + "todo-tree.general.tags": ["TODO", "FIXME", "BUG", "HACK", "NOTE", "OPTIMIZE", "CRITICAL"], + "todo-tree.highlights.customHighlight": { + "TODO": {"icon": "check", "foreground": "#000", "background": "#ffbd2e", "iconColour": "#ffbd2e"}, + "FIXME": {"icon": "alert", "foreground": "#fff", "background": "#f06292", "iconColour": "#f06292"}, + "CRITICAL": {"icon": "flame", "foreground": "#fff", "background": "#f00", "iconColour": "#f00"}, + "BUG": {"icon": "bug", "foreground": "#fff", "background": "#ff6347", "iconColour": "#ff6347"}, + "OPTIMIZE": {"icon": "zap", "foreground": "#000", "background": "#64dd17", "iconColour": "#64dd17"} + }, + + // ===== OTHER ===== + "prettier.enable": false, + "git.autofetch": true, + "workbench.colorTheme": "Default Dark Modern" +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..0c89b13 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,490 @@ +{ + // ============================================================================ + // KaririCode\Parser - VS Code Tasks (Makefile Integration) + // ============================================================================ + // Integrates Makefile targets with VS Code task runner + // Access via: Ctrl+Shift+B or Terminal > Run Task + // ============================================================================ + + "version": "2.0.0", + "tasks": [ + // ===== SETUP & INSTALLATION ===== + { + "label": "Install Dependencies", + "type": "shell", + "command": "make install", + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared", + "showReuseMessage": true, + "clear": false + }, + "problemMatcher": [] + }, + { + "label": "Update Dependencies", + "type": "shell", + "command": "make update", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + + // ===== TESTING ===== + { + "label": "Run All Tests", + "type": "shell", + "command": "make test", + "group": { + "kind": "test", + "isDefault": true + }, + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "shared", + "showReuseMessage": false, + "clear": true + }, + "problemMatcher": [] + }, + { + "label": "Run Unit Tests", + "type": "shell", + "command": "make test-unit", + "group": "test", + "presentation": { + "reveal": "always", + "focus": true, + "panel": "shared", + "clear": true + }, + "problemMatcher": [] + }, + { + "label": "Run Integration Tests", + "type": "shell", + "command": "make test-integration", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Generate Coverage Report", + "type": "shell", + "command": "make coverage", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Open Coverage Report", + "type": "shell", + "command": "xdg-open coverage/html/index.html || open coverage/html/index.html", + "group": "test", + "presentation": { + "reveal": "never" + }, + "problemMatcher": [] + }, + { + "label": "Run Mutation Tests", + "type": "shell", + "command": "make mutation", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + + // ===== STATIC ANALYSIS ===== + { + "label": "Run All Analysis", + "type": "shell", + "command": "make analyse", + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "shared", + "showReuseMessage": false, + "clear": true + }, + "problemMatcher": [ + "$phpcs", + { + "owner": "phpstan", + "fileLocation": ["relative", "${workspaceFolder}"], + "pattern": { + "regexp": "^\\s*(.*):(\\d+)\\s*(.*)$", + "file": 1, + "line": 2, + "message": 3 + } + } + ] + }, + { + "label": "Run PHPStan", + "type": "shell", + "command": "make phpstan", + "group": "build", + "presentation": { + "reveal": "always", + "focus": true, + "panel": "shared", + "clear": true + }, + "problemMatcher": [] + }, + { + "label": "Run Psalm", + "type": "shell", + "command": "make psalm", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Run Psalm Taint Analysis", + "type": "shell", + "command": "make psalm-taint", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + + // ===== CODE STYLE ===== + { + "label": "Check Coding Standards", + "type": "shell", + "command": "make cs-check", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": ["$phpcs"] + }, + { + "label": "Fix Coding Standards", + "type": "shell", + "command": "make cs-fix", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Format Code (PHP-CS-Fixer)", + "type": "shell", + "command": "make format", + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared", + "showReuseMessage": false + }, + "problemMatcher": [] + }, + { + "label": "Format Code (Dry Run)", + "type": "shell", + "command": "make format-dry", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Lint PHP Files", + "type": "shell", + "command": "make lint", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + + // ===== QUALITY CHECKS ===== + { + "label": "Run All Quality Checks", + "type": "shell", + "command": "make check", + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "shared", + "showReuseMessage": false, + "clear": true + }, + "problemMatcher": [] + }, + { + "label": "Validate Composer", + "type": "shell", + "command": "make validate", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Security Audit", + "type": "shell", + "command": "make security", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Check Outdated Dependencies", + "type": "shell", + "command": "make outdated", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + + // ===== CI/CD ===== + { + "label": "Run CI Pipeline", + "type": "shell", + "command": "make ci", + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "dedicated", + "showReuseMessage": false, + "clear": true + }, + "problemMatcher": [] + }, + { + "label": "Run Full CI Pipeline", + "type": "shell", + "command": "make ci-full", + "group": "build", + "presentation": { + "reveal": "always", + "focus": true, + "panel": "dedicated", + "clear": true + }, + "problemMatcher": [] + }, + { + "label": "Run CD Pipeline", + "type": "shell", + "command": "make cd", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "dedicated" + }, + "problemMatcher": [] + }, + + // ===== BENCHMARKING ===== + { + "label": "Run Benchmarks", + "type": "shell", + "command": "make benchmark", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Compare Benchmarks", + "type": "shell", + "command": "make benchmark-compare", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + + // ===== CLEANUP ===== + { + "label": "Clean Build Artifacts", + "type": "shell", + "command": "make clean", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Deep Clean (including vendor)", + "type": "shell", + "command": "make clean-all", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + + // ===== DOCKER TASKS ===== + { + "label": "Docker: Pull Image", + "type": "shell", + "command": "make docker-pull", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Docker: Run Tests", + "type": "shell", + "command": "make docker-test", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Docker: Run CI", + "type": "shell", + "command": "make docker-ci", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "dedicated" + }, + "problemMatcher": [] + }, + { + "label": "Docker: Open Shell", + "type": "shell", + "command": "make docker-shell", + "group": "none", + "isBackground": false, + "presentation": { + "reveal": "always", + "panel": "dedicated", + "focus": true + }, + "problemMatcher": [] + }, + + // ===== UTILITIES ===== + { + "label": "Show Project Stats", + "type": "shell", + "command": "make stats", + "group": "none", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Show Project Info", + "type": "shell", + "command": "make info", + "group": "none", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "Count Lines of Code", + "type": "shell", + "command": "make loc", + "group": "none", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + + // ===== PRE-COMMIT ===== + { + "label": "Run Pre-Commit Checks", + "type": "shell", + "command": "make pre-commit", + "group": "build", + "presentation": { + "reveal": "always", + "focus": true, + "panel": "shared", + "clear": true + }, + "problemMatcher": [] + }, + { + "label": "Install Git Hooks", + "type": "shell", + "command": "make install-hooks", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + } + ] +} diff --git a/composer.json b/composer.json index 3268faf..5379c3d 100644 --- a/composer.json +++ b/composer.json @@ -35,27 +35,29 @@ } }, "require": { - "php": "^8.3" + "php": "^8.4" }, "require-dev": { - "phpunit/phpunit": "12.4.1", - "friendsofphp/php-cs-fixer": "3.89.0", - "phpstan/phpstan": "^2.0", + "friendsofphp/php-cs-fixer": "^3.89", + "infection/infection": "^0.31", + "phpbench/phpbench": "^1.3", + "phpstan/phpstan": "^2.1", "phpstan/phpstan-strict-rules": "^2.0", - "phpmd/phpmd": "^2.15", - "rector/rector": "2.2.4" - }, - "scripts-descriptions": { - "check-ready": "Verify DevKit environment is properly configured" + "phpunit/phpunit": "^12.4", + "squizlabs/php_codesniffer": "^4.0", + "symfony/var-dumper": "^7.3", + "vimeo/psalm": "^6.13" }, "config": { "sort-packages": true, "optimize-autoloader": true, "preferred-install": "dist", "allow-plugins": { - "php-http/discovery": true + "php-http/discovery": true, + "dealerdirect/phpcodesniffer-composer-installer": true, + "infection/extension-installer": true } }, "minimum-stability": "dev", "prefer-stable": true -} \ No newline at end of file +} diff --git a/infection.json b/infection.json new file mode 100644 index 0000000..cad07f6 --- /dev/null +++ b/infection.json @@ -0,0 +1,32 @@ +{ + "$schema": "vendor/infection/infection/resources/schema.json", + "source": { + "directories": [ + "src" + ] + }, + "timeout": 30, + "logs": { + "text": "infection.log", + "html": "infection.html", + "summary": "infection-summary.log", + "debug": "infection-debug.log", + "perMutator": "infection-per-mutator.md" + }, + "tmpDir": "var/cache/infection", + "phpUnit": { + "configDir": ".", + "customPath": "vendor/bin/phpunit" + }, + "minMsi": 80, + "minCoveredMsi": 90, + "mutators": { + "@default": true, + "@function_signature": false, + "MethodCallRemoval": { + "ignore": [] + } + }, + "testFramework": "phpunit", + "bootstrap": "vendor/autoload.php" +} diff --git a/phpbench.json b/phpbench.json new file mode 100644 index 0000000..aae4e40 --- /dev/null +++ b/phpbench.json @@ -0,0 +1,37 @@ +{ + "$schema": "./vendor/phpbench/phpbench/phpbench.schema.json", + "runner.bootstrap": "vendor/autoload.php", + "runner.path": "benchmarks", + "runner.php_config": { + "memory_limit": "1G" + }, + "runner.executors": { + "profiling": { + "executor": "local", + "php_config": { + "xdebug.mode": "profile", + "xdebug.output_dir": "build/profile" + } + } + }, + "report.generators": { + "table": { + "cols": [ + "benchmark", + "subject", + "revs", + "its", + "mem_peak", + "best", + "mean", + "mode", + "worst", + "stdev", + "rstdev", + "diff" + ] + } + }, + "runner.iterations": 10, + "runner.revs": 1000 +} diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..c423cc0 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,50 @@ + + + Coding standard with exceptions for PHP keyword conflicts + + + src + tests + + + vendor/* + var/* + build/* + coverage/* + public/index.php + *.blade.php + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/phpstan.neon b/phpstan.neon index 0582e97..6658f4c 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,129 +1,32 @@ -# -# KaririCode DevKit - PHPStan Configuration -# -# Professional static analysis configuration with maximum strictness level. -# Ensures type safety, catches bugs early, and enforces best practices. -# -# @see https://phpstan.org/config-reference -# @see https://phpstan.org/user-guide/rule-levels -# - parameters: - # Analysis Level (0-9, 9 being the strictest) level: max - - # Paths to analyze paths: - src - - tests - - # Files/directories to exclude excludePaths: - - tests/Fixtures/* - - vendor/* + - tests/Fixtures (?) + tmpDir: var/cache/phpstan - # Report unmatched ignored errors - reportUnmatchedIgnoredErrors: true + # Allow analysis even with no files initially + reportUnmatchedIgnoredErrors: false + treatPhpDocTypesAsCertain: false - # Treat PHPDoc types as authoritative - treatPhpDocTypesAsCertain: true + # Case sensitivity checks + checkClassCaseSensitivity: true + checkFunctionNameCase: true + checkInternalClassCaseSensitivity: true - # Check missing typehints - checkMissingCallableSignature: true + # Strict production quality rules + checkExplicitMixedMissingReturn: true checkUninitializedProperties: true checkTooWideReturnTypesInProtectedAndPublicMethods: true - checkImplicitMixed: true - checkBenevolentUnionTypes: true - - # Universal object crates (disable magic get/set for strict typing) - universalObjectCratesClasses: [] - - # Type aliases for better readability - typeAliases: - mixed: 'mixed' - # Bleeding edge features (use latest PHPStan capabilities) + # Scope pollution prevention polluteScopeWithLoopInitialAssignments: false polluteScopeWithAlwaysIterableForeach: false - checkAlwaysTrueCheckTypeFunctionCall: true - checkAlwaysTrueInstanceof: true - checkAlwaysTrueStrictComparison: true - checkExplicitMixedMissingReturn: true - checkFunctionNameCase: true - checkInternalClassCaseSensitivity: true - checkMissingIterableValueType: true - checkMissingVarTagTypehint: true - - # Exception handling - exceptions: - check: - missingCheckedExceptionInThrows: true - tooWideThrowType: true - checkedExceptionClasses: [] - implicitThrows: true - - # Ignore errors (use sparingly, prefer fixing the code) - ignoreErrors: - # Example: ignore specific errors if absolutely necessary - # - '#PHPDoc tag @var for variable \$.*#' - - # Bootstrap file (if needed for setup) - # bootstrapFiles: - # - tests/bootstrap.php - - # Parallel processing - parallel: - jobSize: 20 - maximumNumberOfProcesses: 4 - minimumNumberOfJobsPerProcess: 2 - - # Include PHPStan extensions - includes: - # Uncomment as needed: - # - vendor/phpstan/phpstan-phpunit/extension.neon - # - vendor/phpstan/phpstan-strict-rules/rules.neon - # - vendor/phpstan/phpstan-deprecation-rules/rules.neon - - # Stub files (for better understanding of external code) - stubFiles: [] - - # Custom rules - # customRulesetUsed: true - -# Services and rules configuration -services: - # Enable bleeding edge rules - - - class: PHPStan\Rules\BooleansInConditions\BooleanInBooleanAndRule - tags: - - phpstan.rules.rule - - - class: PHPStan\Rules\BooleansInConditions\BooleanInBooleanNotRule - tags: - - phpstan.rules.rule - - - class: PHPStan\Rules\BooleansInConditions\BooleanInBooleanOrRule - tags: - - phpstan.rules.rule - - - class: PHPStan\Rules\BooleansInConditions\BooleanInElseIfConditionRule - tags: - - phpstan.rules.rule - - - class: PHPStan\Rules\BooleansInConditions\BooleanInIfConditionRule - tags: - - phpstan.rules.rule - - - class: PHPStan\Rules\BooleansInConditions\BooleanInTernaryOperatorRule - tags: - - phpstan.rules.rule -# Conditional configuration based on installed extensions -conditionalTags: - PHPStan\Rules\PHPUnit\*: - phpstan.rules.rule: %phpunit.enabled% + # PHPDoc flexibility + reportMaybesInMethodSignatures: false + reportStaticMethodSignatures: false -# Include strict rules if available -# Uncomment when phpstan/phpstan-strict-rules is installed -# includes: -# - vendor/phpstan/phpstan-strict-rules/rules.neon \ No newline at end of file +includes: + - vendor/phpstan/phpstan-strict-rules/rules.neon diff --git a/phpunit.xml b/phpunit.xml index 6afc55f..fd3e50d 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,56 +1,45 @@ - - + bootstrap="vendor/autoload.php" colors="true" beStrictAboutOutputDuringTests="true" + failOnRisky="true" failOnWarning="true" cacheDirectory=".phpunit.cache" + displayDetailsOnTestsThatTriggerDeprecations="true" + displayDetailsOnTestsThatTriggerErrors="true" displayDetailsOnTestsThatTriggerNotices="true" + displayDetailsOnTestsThatTriggerWarnings="true"> - - tests/Unit + + tests/Unit - - tests/Integration + + tests/Integration + + + tests/Functional - - - + - src + src - - vendor - devkit - tests - + + - - - + + + - - - + + + - - - - - - + + + + + - diff --git a/rector.php b/rector.php deleted file mode 100644 index 29bb6aa..0000000 --- a/rector.php +++ /dev/null @@ -1,154 +0,0 @@ -withPaths([ - __DIR__ . '/src', - __DIR__ . '/tests', - ]) - ->withSkip([ - // Skip test fixtures - __DIR__ . '/tests/Fixtures', - ]) - // PHP 8.3 features and best practices - ->withPhpSets(php83: true) - ->withPreparedSets( - deadCode: true, - codeQuality: true, - codingStyle: true, - typeDeclarations: true, - privatization: true, - naming: true, - instanceOf: true, - earlyReturn: true, - strictBooleans: true - ) - ->withSets([ - LevelSetList::UP_TO_PHP_83, - SetList::TYPE_DECLARATION, - SetList::EARLY_RETURN, - SetList::CODE_QUALITY, - PHPUnitSetList::PHPUNIT_100, - PHPUnitSetList::PHPUNIT_CODE_QUALITY, - ]) - ->withRules([ - // PHP 8.0+ - InlineConstructorDefaultToPropertyRector::class, - ClassPropertyAssignToConstructorPromotionRector::class, - MixedTypeRector::class, - - // PHP 8.1+ - ReadOnlyPropertyRector::class, - FinalizePublicClassConstantRector::class, - FirstClassCallableRector::class, - - // PHP 8.2+ - ReadOnlyClassRector::class, - - // PHP 8.3+ - AddOverrideAttributeToOverriddenMethodsRector::class, - - // Code Quality - FlipTypeControlToUseExclusiveTypeRector::class, - RemoveUnusedPrivatePropertyRector::class, - RemoveUnusedPrivateMethodParameterRector::class, - RemoveUselessParamTagRector::class, - RemoveUselessReturnTagRector::class, - RemoveConcatAutocastRector::class, - RemoveAlwaysTrueIfConditionRector::class, - - // Coding Style - StaticClosureRector::class, - StaticArrowFunctionRector::class, - CatchExceptionNameMatchingTypeRector::class, - MakeInheritedMethodVisibilitySameAsParentRector::class, - UseClassKeywordForClassNameResolutionRector::class, - CountArrayToEmptyArrayComparisonRector::class, - PostIncDecToPreIncDecRector::class, - - // Early Return - ChangeAndIfToEarlyReturnRector::class, - ChangeIfElseValueAssignToEarlyReturnRector::class, - ChangeOrIfContinueToMultiContinueRector::class, - PreparedValueToEarlyReturnRector::class, - - // Type Declarations - AddVoidReturnTypeWhereNoReturnRector::class, - ReturnTypeFromStrictNativeCallRector::class, - TypedPropertyFromStrictConstructorRector::class, - EmptyOnNullableObjectToInstanceOfRector::class, - - // Naming - RenameVariableToMatchMethodCallReturnTypeRector::class, - RenameParamToMatchTypeRector::class, - - // Strict Rules - DisallowedEmptyRuleFixerRector::class, - - // PHPUnit - PreferPHPUnitThisCallRector::class, - ]) - ->withSkipRules([ - // Skip rules that conflict with our code style - EncapsedStringsToSprintfRector::class, - NewlineAfterStatementRector::class, - ]) - ->withImportNames( - importShortClasses: false, - removeUnusedImports: true - ) - ->withParallel() - ->withCache( - cacheDirectory: __DIR__ . '/.rector_cache' - ); diff --git a/src/Length.php b/src/Length.php index 3c2baf4..aeb9dd7 100644 --- a/src/Length.php +++ b/src/Length.php @@ -25,5 +25,6 @@ class Length public function __construct( public readonly int $min = 0, public readonly int $max = PHP_INT_MAX, - ) {} + ) { + } } diff --git a/src/UserId.php b/src/UserId.php index b3cac37..79b7e21 100644 --- a/src/UserId.php +++ b/src/UserId.php @@ -28,7 +28,7 @@ public function __construct( public string $value, ) { if (empty($value)) { - throw new InvalidArgumentException("User ID cannot be empty."); + throw new InvalidArgumentException('User ID cannot be empty.'); } } diff --git a/src/UserProfile.php b/src/UserProfile.php index 0255b1a..7cc084e 100644 --- a/src/UserProfile.php +++ b/src/UserProfile.php @@ -9,6 +9,7 @@ use InvalidArgumentException; use JsonSerializable; use Random\Randomizer; +use SensitiveParameter; use Stringable; // -------------------------------------------------------------- @@ -51,26 +52,24 @@ final readonly class UserProfile implements JsonSerializable, Stringable { public const string MODEL = 'UserProfile'; + public const int VERSION = 1; public function __construct( #[Length(min: 1, max: 50)] public string $id, - #[Length(min: 2, max: 120)] public string $name, - public Email $email, public UserRole $role = UserRole::VIEWER, public UserStatus $status = UserStatus::ACTIVE, - - #[\SensitiveParameter] + #[SensitiveParameter] public ?string $twoFactorSecret = null, - public ?array $meta = null, public ?DateTimeImmutable $createdAt = null, public ?DateTimeImmutable $updatedAt = null, - ) {} + ) { + } /** * Creates a new UserProfile instance with a generated ID and current timestamps. @@ -159,7 +158,7 @@ public function promote(): self twoFactorSecret: $this->twoFactorSecret, meta: $this->meta, createdAt: $this->createdAt, - updatedAt: new DateTimeImmutable() + updatedAt: new DateTimeImmutable(), ); } @@ -174,11 +173,11 @@ public function suspend(): self twoFactorSecret: $this->twoFactorSecret, meta: $this->meta, createdAt: $this->createdAt, - updatedAt: new DateTimeImmutable() + updatedAt: new DateTimeImmutable(), ); } - public function with2FA(#[\SensitiveParameter] string $secret): self + public function with2FA(#[SensitiveParameter] string $secret): self { return new self( id: $this->id, @@ -189,7 +188,7 @@ public function with2FA(#[\SensitiveParameter] string $secret): self twoFactorSecret: $secret, meta: $this->meta, createdAt: $this->createdAt, - updatedAt: new DateTimeImmutable() + updatedAt: new DateTimeImmutable(), ); } @@ -204,7 +203,7 @@ public function withMeta(array $meta): self twoFactorSecret: $this->twoFactorSecret, meta: $meta, createdAt: $this->createdAt, - updatedAt: new DateTimeImmutable() + updatedAt: new DateTimeImmutable(), ); } @@ -224,7 +223,7 @@ public function jsonSerialize(): array 'version' => self::VERSION, 'id' => $this->id, 'name' => $this->name, - 'email' => (string)$this->email, + 'email' => (string) $this->email, 'role' => $this->role->value, 'status' => $this->status->value, 'has2FA' => $this->has2FA(), @@ -249,6 +248,7 @@ public function __toString(): string private static function hydrateEmail(array $data): Email { $emailInput = $data['email'] ?? ''; + return $emailInput instanceof Email ? $emailInput : new Email($emailInput); } diff --git a/tests/Integration/UserProfileFlowTest.php b/tests/Integration/UserProfileFlowTest.php index dd80e88..424c260 100644 --- a/tests/Integration/UserProfileFlowTest.php +++ b/tests/Integration/UserProfileFlowTest.php @@ -85,7 +85,7 @@ public function itHandlesACompleteUserLifecycleFlow(): void // updatedAt must be newer than createdAt $this->assertGreaterThan( new DateTimeImmutable($finalJson['createdAt']), - new DateTimeImmutable($finalJson['updatedAt']) + new DateTimeImmutable($finalJson['updatedAt']), ); } } diff --git a/tests/Unit/UserProfileTest.php b/tests/Unit/UserProfileTest.php index 076432b..95d808e 100644 --- a/tests/Unit/UserProfileTest.php +++ b/tests/Unit/UserProfileTest.php @@ -29,7 +29,7 @@ public function itCreatesNewUserWithFactory(): void $user = UserProfile::new( name: 'Utilizador Teste', email: 'teste@exemplo.com', - role: UserRole::EDITOR + role: UserRole::EDITOR, ); $this->assertInstanceOf(UserProfile::class, $user); @@ -72,7 +72,7 @@ public function itHydratesFromArray(): void $this->assertSame(['key' => 'value'], $user->meta); $this->assertSame( $expectedCreated->format('Y-m-d\TH:i:sP'), - $user->createdAt?->format('Y-m-d\TH:i:sP') + $user->createdAt?->format('Y-m-d\TH:i:sP'), ); $this->assertNull($user->updatedAt); @@ -221,7 +221,7 @@ public function itSerializesCorrectly(): void $this->assertSame("UserProfile#{$id}", (string) $user); // Teste displayLabel - $this->assertSame("Serializar (viewer)", $user->displayLabel()); + $this->assertSame('Serializar (viewer)', $user->displayLabel()); // Teste jsonSerialize $json = $user->jsonSerialize(); diff --git a/tests/Unit/ValueObjectsTest.php b/tests/Unit/ValueObjectsTest.php index e336a7d..5f7ae1b 100644 --- a/tests/Unit/ValueObjectsTest.php +++ b/tests/Unit/ValueObjectsTest.php @@ -39,7 +39,7 @@ public function emailThrowsExceptionForInvalidValue(): void { // Expect an InvalidArgumentException to be thrown for an invalid email format $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage("Invalid email: email-invalido"); + $this->expectExceptionMessage('Invalid email: email-invalido'); // Attempt to create an Email object with an invalid string, which should trigger the exception new Email('email-invalido'); @@ -67,7 +67,7 @@ public function userIdThrowsExceptionForEmptyValue(): void { // Expect an InvalidArgumentException to be thrown for an empty user ID $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage("User ID cannot be empty."); + $this->expectExceptionMessage('User ID cannot be empty.'); new UserId(''); // Isto deve falhar }