'; /** * @return non-empty-string */ public static function getContents( string $current_dir, ?string $suggested_dir, int $level, string $vendor_dir ): string { $paths = self::getPaths($current_dir, $suggested_dir); $template = str_replace( '', implode("\n ", $paths), self::TEMPLATE ); if (is_dir($current_dir . DIRECTORY_SEPARATOR . $vendor_dir)) { $template = str_replace( '', '', $template ); } else { $template = str_replace( '', '', $template ); } /** @var non-empty-string */ return str_replace( 'errorLevel="1"', 'errorLevel="' . $level . '"', $template ); } public static function createBareConfig( string $current_dir, ?string $suggested_dir, string $vendor_dir ): Config { $config_contents = self::getContents($current_dir, $suggested_dir, 1, $vendor_dir); return Config::loadFromXML($current_dir, $config_contents); } /** * @param array $issues */ public static function getLevel(array $issues, int $counted_types): int { if ($counted_types === 0) { $counted_types = 1; } $issues_at_level = []; foreach ($issues as $issue) { $issue_type = $issue->type; $issue_level = $issue->error_level; if ($issue_level < 1) { continue; } // exclude some directories that are probably ignorable if (strpos($issue->file_path, 'vendor') || strpos($issue->file_path, 'stub')) { continue; } if (!isset($issues_at_level[$issue_level][$issue_type])) { $issues_at_level[$issue_level][$issue_type] = 0; } $issues_at_level[$issue_level][$issue_type] += 100/$counted_types; } foreach ($issues_at_level as $level => $issues) { ksort($issues); // remove any issues where < 0.1% of expressions are affected $filtered_issues = array_filter( $issues, function ($amount): bool { return $amount > 0.1; } ); if (array_sum($filtered_issues) > 0.5) { $issues_at_level[$level] = $filtered_issues; } else { unset($issues_at_level[$level]); } } if (!$issues_at_level) { return 1; } if (count($issues_at_level) === 1) { return array_keys($issues_at_level)[0] + 1; } return max(...array_keys($issues_at_level)) + 1; } /** * @return non-empty-list */ public static function getPaths(string $current_dir, ?string $suggested_dir): array { $replacements = []; if ($suggested_dir) { if (is_dir($current_dir . DIRECTORY_SEPARATOR . $suggested_dir)) { $replacements[] = ''; } else { $bad_dir_path = $current_dir . DIRECTORY_SEPARATOR . $suggested_dir; throw new ConfigCreationException( 'The given path "' . $bad_dir_path . '" does not appear to be a directory' ); } } elseif (is_dir($current_dir . DIRECTORY_SEPARATOR . 'src')) { $replacements[] = ''; } else { $composer_json_location = Composer::getJsonFilePath($current_dir); if (!file_exists($composer_json_location)) { throw new ConfigCreationException( 'Problem during config autodiscovery - could not find composer.json during initialization.' ); } if (!$composer_json = json_decode(file_get_contents($composer_json_location), true)) { throw new ConfigCreationException('Invalid composer.json at ' . $composer_json_location); } if (!is_array($composer_json)) { throw new ConfigCreationException('Invalid composer.json at ' . $composer_json_location); } $replacements = self::getPsr4Or0Paths($current_dir, $composer_json); if (!$replacements) { throw new ConfigCreationException( 'Could not located any PSR-0 or PSR-4-compatible paths in ' . $composer_json_location ); } } return $replacements; } /** * @return list * @psalm-suppress MixedAssignment * @psalm-suppress MixedArgument */ private static function getPsr4Or0Paths(string $current_dir, array $composer_json): array { $psr_paths = array_merge( $composer_json['autoload']['psr-4'] ?? [], $composer_json['autoload']['psr-0'] ?? [] ); if (!$psr_paths) { return self::guessPhpFileDirs($current_dir); } $nodes = []; foreach ($psr_paths as $paths) { if (!is_array($paths)) { $paths = [$paths]; } foreach ($paths as $path) { if ($path === '') { $nodes = array_merge( $nodes, self::guessPhpFileDirs($current_dir) ); continue; } $path = preg_replace('@[/\\\]$@', '', $path, 1); if ($path !== 'tests') { $nodes[] = ''; } } } $nodes = array_unique($nodes); sort($nodes); return $nodes; } /** * @return list */ private static function guessPhpFileDirs(string $current_dir): array { $nodes = []; /** @var string[] */ $php_files = array_merge( glob($current_dir . DIRECTORY_SEPARATOR . '*.php', GLOB_NOSORT), glob($current_dir . DIRECTORY_SEPARATOR . '**/*.php', GLOB_NOSORT), glob($current_dir . DIRECTORY_SEPARATOR . '**/**/*.php', GLOB_NOSORT) ); foreach ($php_files as $php_file) { $php_file = str_replace($current_dir . DIRECTORY_SEPARATOR, '', $php_file); $parts = explode(DIRECTORY_SEPARATOR, $php_file); if (!$parts[0]) { array_shift($parts); } if ($parts[0] === 'vendor' || $parts[0] === 'tests') { continue; } if (count($parts) === 1) { $nodes[] = ''; } else { $nodes[] = ''; } } return array_values(array_unique($nodes)); } }