Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Here are the available rules:

### 1. Find duplicated definitions contents (`duplicated-contents`)

Some definitions have similar masks, even identical contents:
Some definitions have similar patterns, even identical contents:

```php
use Behat\Step\When;
Expand All @@ -53,7 +53,7 @@ public function loadUserProfile()
}
```

Better use a one definition with single mask, to make your tests more precise and easier to maintain.
Better use a one definition with single pattern, to make your tests more precise and easier to maintain.

<br>

Expand Down
2 changes: 1 addition & 1 deletion rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
->withSkip([
\Rector\Php55\Rector\String_\StringClassNameToClassConstantRector::class => [
// keep string class names
__DIR__ . '/src/Resolver/ClassMethodMasksResolver.php',
__DIR__ . '/src/Resolver/ClassMethodPatternResolver.php',
],
])
->withImportNames()
Expand Down
14 changes: 7 additions & 7 deletions src/Analyzer/ContextDefinitionsAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use PhpParser\NodeFinder;
use PhpParser\PrettyPrinter\Standard;
use Rector\Behastan\PhpParser\SimplePhpParser;
use Rector\Behastan\Resolver\ClassMethodMasksResolver;
use Rector\Behastan\Resolver\ClassMethodPatternResolver;
use Rector\Behastan\ValueObject\ContextDefinition;
use Symfony\Component\Finder\SplFileInfo;

Expand All @@ -25,7 +25,7 @@ public function __construct(
private readonly SimplePhpParser $simplePhpParser,
private readonly NodeFinder $nodeFinder,
private readonly Standard $printerStandard,
private readonly ClassMethodMasksResolver $classMethodMasksResolver,
private readonly ClassMethodPatternResolver $classMethodPatternResolver,
) {
}

Expand Down Expand Up @@ -84,19 +84,19 @@ public function resolveAndGroupByContentHash(array $contextFileInfos): array
}

$classMethodHash = $this->createClassMethodHash($classMethod);
$rawMasks = $this->classMethodMasksResolver->resolve($classMethod);
$rawPatterns = $this->classMethodPatternResolver->resolve($classMethod);

// no masks :(
if ($rawMasks === []) {
// no patterns found :(
if ($rawPatterns === []) {
continue;
}

$contextDefinition = new ContextDefinition(
$contextFileInfo->getRealPath(),
$className,
$classMethod->name->toString(),
// @todo what about multiple masks?
$rawMasks[0],
// @todo what about multiple patterns?
$rawPatterns[0],
$classMethod->getStartLine()
);

Expand Down
29 changes: 0 additions & 29 deletions src/Analyzer/MaskAnalyzer.php

This file was deleted.

29 changes: 29 additions & 0 deletions src/Analyzer/PatternAnalyzer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Rector\Behastan\Analyzer;

final class PatternAnalyzer
{
/**
* @var string
*/
private const PATTERN_REGEX = '#(\:[\W\w]+)#';

public static function isRegex(string $rawPattern): bool
{
if (str_starts_with($rawPattern, '/')) {
return true;
}

return str_ends_with($rawPattern, '#');
}

public static function isValuePattern(string $rawPattern): bool
{
preg_match(self::PATTERN_REGEX, $rawPattern, $match);

return $match !== [];
}
}
56 changes: 25 additions & 31 deletions src/Analyzer/UnusedDefinitionsAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@

namespace Rector\Behastan\Analyzer;

use Entropy\Console\Output\OutputPrinter;
use Nette\Utils\Strings;
use Rector\Behastan\DefinitionMasksExtractor;
use Rector\Behastan\DefinitionPatternsExtractor;
use Rector\Behastan\UsedInstructionResolver;
use Rector\Behastan\ValueObject\Mask\AbstractMask;
use Rector\Behastan\ValueObject\Mask\ExactMask;
use Rector\Behastan\ValueObject\Mask\NamedMask;
use Rector\Behastan\ValueObject\Mask\RegexMask;
use Rector\Behastan\ValueObject\Mask\SkippedMask;
use Rector\Behastan\ValueObject\MaskCollection;
use Rector\Behastan\ValueObject\Pattern\AbstractPattern;
use Rector\Behastan\ValueObject\Pattern\ExactPattern;
use Rector\Behastan\ValueObject\Pattern\NamedPattern;
use Rector\Behastan\ValueObject\Pattern\RegexPattern;
use Rector\Behastan\ValueObject\Pattern\SkippedPattern;
use Rector\Behastan\ValueObject\PatternCollection;
use Symfony\Component\Finder\SplFileInfo;
use Webmozart\Assert\Assert;

Expand All @@ -25,21 +24,21 @@
/**
* @var string
*/
private const MASK_VALUE_REGEX = '#(\:[\W\w]+)#';
private const PATTERN_VALUE_REGEX = '#(\:[\W\w]+)#';

public function __construct(
private UsedInstructionResolver $usedInstructionResolver,
private DefinitionMasksExtractor $definitionMasksExtractor,
private DefinitionPatternsExtractor $definitionPatternsExtractor,
) {
}

/**
* @param SplFileInfo[] $contextFiles
* @param SplFileInfo[] $featureFiles
*
* @return AbstractMask[]
* @return AbstractPattern[]
*/
public function analyse(array $contextFiles, array $featureFiles, MaskCollection $maskCollection): array
public function analyse(array $contextFiles, array $featureFiles, PatternCollection $patternCollection): array
{
Assert::allIsInstanceOf($contextFiles, SplFileInfo::class);
foreach ($contextFiles as $contextFile) {
Expand All @@ -51,25 +50,20 @@ public function analyse(array $contextFiles, array $featureFiles, MaskCollection
Assert::endsWith($featureFile->getFilename(), '.feature');
}

$maskCollection = $this->definitionMasksExtractor->extract($contextFiles);
$patternCollection = $this->definitionPatternsExtractor->extract($contextFiles);

$featureInstructions = $this->usedInstructionResolver->resolveInstructionsFromFeatureFiles($featureFiles);
//$maskProgressBar = $this->outputPrinter->createProgressBar($maskCollection->count());

$unusedMasks = [];
foreach ($maskCollection->all() as $mask) {
// $maskProgressBar->advance();

if ($this->isMaskUsed($mask, $featureInstructions)) {
$unusedPatterns = [];
foreach ($patternCollection->all() as $pattern) {
if ($this->isPatternUsed($pattern, $featureInstructions)) {
continue;
}

$unusedMasks[] = $mask;
$unusedPatterns[] = $pattern;
}

// $maskProgressBar->finish();

return $unusedMasks;
return $unusedPatterns;
}

/**
Expand All @@ -90,27 +84,27 @@ private function isRegexDefinitionUsed(string $regexBehatDefinition, array $feat
/**
* @param string[] $featureInstructions
*/
private function isMaskUsed(AbstractMask $mask, array $featureInstructions): bool
private function isPatternUsed(AbstractPattern $pattern, array $featureInstructions): bool
{
if ($mask instanceof SkippedMask) {
if ($pattern instanceof SkippedPattern) {
return true;
}

// is used?
if ($mask instanceof ExactMask && in_array($mask->mask, $featureInstructions, true)) {
if ($pattern instanceof ExactPattern && in_array($pattern->pattern, $featureInstructions, true)) {
return true;
}

// is used?
if ($mask instanceof RegexMask && $this->isRegexDefinitionUsed($mask->mask, $featureInstructions)) {
if ($pattern instanceof RegexPattern && $this->isRegexDefinitionUsed($pattern->pattern, $featureInstructions)) {
return true;
}

if ($mask instanceof NamedMask) {
// normalize :mask definition to regex
$regexMask = '#' . Strings::replace($mask->mask, self::MASK_VALUE_REGEX, '(.*?)') . '#';
if ($pattern instanceof NamedPattern) {
// normalize :pattern definition to regex
$regexPattern = '#' . Strings::replace($pattern->pattern, self::PATTERN_VALUE_REGEX, '(.*?)') . '#';

if ($this->isRegexDefinitionUsed($regexMask, $featureInstructions)) {
if ($this->isRegexDefinitionUsed($regexPattern, $featureInstructions)) {
return true;
}
}
Expand Down
16 changes: 8 additions & 8 deletions src/Command/AnalyzeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@
use Entropy\Console\Contract\CommandInterface;
use Entropy\Console\Enum\ExitCode;
use Entropy\Console\Output\OutputPrinter;
use Rector\Behastan\DefinitionMasksExtractor;
use Rector\Behastan\DefinitionPatternsExtractor;
use Rector\Behastan\Finder\BehatMetafilesFinder;
use Rector\Behastan\Reporting\MaskCollectionStatsPrinter;
use Rector\Behastan\Reporting\PatternCollectionStatsPrinter;
use Rector\Behastan\RulesRegistry;
use Rector\Behastan\ValueObject\RuleError;
use Webmozart\Assert\Assert;

final readonly class AnalyzeCommand implements CommandInterface
{
public function __construct(
private DefinitionMasksExtractor $definitionMasksExtractor,
private MaskCollectionStatsPrinter $maskCollectionStatsPrinter,
private DefinitionPatternsExtractor $definitionPatternsExtractor,
private PatternCollectionStatsPrinter $patternCollectionStatsPrinter,
private OutputPrinter $outputPrinter,
private RulesRegistry $rulesRegistry,
) {
Expand Down Expand Up @@ -65,12 +65,12 @@ public function run(?string $projectDirectory = null, array $skip = []): int
count($contextFileInfos),
count($featureFileInfos)
));
$this->outputPrinter->writeln('<fg=yellow>Extracting definitions masks...</>');
$this->outputPrinter->writeln('<fg=yellow>Extracting definitions patterns...</>');

$maskCollection = $this->definitionMasksExtractor->extract($contextFileInfos);
$patternCollection = $this->definitionPatternsExtractor->extract($contextFileInfos);
$this->outputPrinter->newLine();

$this->maskCollectionStatsPrinter->print($maskCollection);
$this->patternCollectionStatsPrinter->print($patternCollection);
$this->outputPrinter->newLine();

$this->outputPrinter->writeln('<fg=yellow>Running analysis...</>');
Expand All @@ -85,7 +85,7 @@ public function run(?string $projectDirectory = null, array $skip = []): int
continue;
}

$ruleErrors = $rule->process($contextFileInfos, $featureFileInfos, $maskCollection, $projectDirectory);
$ruleErrors = $rule->process($contextFileInfos, $featureFileInfos, $patternCollection, $projectDirectory);
$allRuleErrors = array_merge($allRuleErrors, $ruleErrors);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

namespace Rector\Behastan\Contract;

interface MaskInterface
interface PatternInterface
{
}
4 changes: 2 additions & 2 deletions src/Contract/RuleInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Rector\Behastan\Contract;

use Rector\Behastan\Enum\RuleIdentifier;
use Rector\Behastan\ValueObject\MaskCollection;
use Rector\Behastan\ValueObject\PatternCollection;
use Rector\Behastan\ValueObject\RuleError;
use Symfony\Component\Finder\SplFileInfo;

Expand All @@ -20,7 +20,7 @@ interface RuleInterface
public function process(
array $contextFiles,
array $featureFiles,
MaskCollection $maskCollection,
PatternCollection $patternCollection,
string $projectDirectory
): array;

Expand Down
Loading