Skip to content

Commit

Permalink
feat: find inline nowdoc components
Browse files Browse the repository at this point in the history
  • Loading branch information
nerg4l committed Jan 22, 2024
1 parent a39cf01 commit fdcfa74
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 24 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ The command detects the following in your blade and application files:
- `app('translator')->get('key')` any direct `get`method call on the `translator`
- `App::make('translator')->get('key')` any direct `get` method call on the `translator`
- `Lang::get('key')` any `get` static call on the `Lang` facade
- `<<<'blade'` incline components in nowdoc with `blade` label are compiled and their content is scanned.

## Implementation

Expand Down
51 changes: 51 additions & 0 deletions src/BladeNowdocFinder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace CodingSocks\LostInTranslation;

use PhpParser\Node\Scalar\String_;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\FindingVisitor;
use PhpParser\Parser;
use PhpParser\ParserFactory;

class BladeNowdocFinder
{
/** @var \PhpParser\Parser */
private Parser $parser;

/**
* @param \PhpParser\Parser|null $parser
*/
public function __construct(
Parser $parser = null,
) {
$this->parser = $parser ?? (new ParserFactory())->createForHostVersion();
}

/**
* Find occurrences of translations in a string.
*
* @param string $str
* @return \PhpParser\Node[]
*/
public function find(string $str): array
{
$nodes = $this->parser->parse($str);

if (empty($nodes)) {
return [];
}

$visitor = new FindingVisitor(function ($node) {
return $node instanceof String_
&& strtolower($node->getAttribute('docLabel', '')) === 'blade';
});

$traverser = new NodeTraverser();
$traverser->addVisitor($visitor); // For compatibility with ^4.10

$traverser->traverse($nodes);

return $visitor->getFoundNodes();
}
}
71 changes: 49 additions & 22 deletions src/Console/Commands/FindMissingTranslationStrings.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ class FindMissingTranslationStrings extends Command
*/
protected $signature = 'lost-in-translation:find
{locale : The locale to be checked}
{--sorted : Sort the values before printing}';
{--sorted : Sort the values before printing}
{--no-progress : Do not show the progress bar}';

/**
* The console command description.
Expand Down Expand Up @@ -63,21 +64,9 @@ public function handle(LostInTranslation $lit)
return Str::endsWith($file->getExtension(), 'php');
});

$reported = [];
$missing = $this->trackProgress($files, $this->makeMissingTranslationFinderCallback($lit, $locale));

$this->invalidArguments = [];
$this->trackProgress($files, function (SplFileInfo $file) use ($lit, $locale, &$reported) {
$nodes = $lit->findInFile($file);

$translationKeys = $this->resolveFirstArgs($lit, $nodes);

foreach ($translationKeys as $key) {
if (!Lang::has($key, $locale) && !array_key_exists($key, $reported)) {
// TODO: find a better way to check uniqueness
$reported[$key] = true;
}
}
})->clear();
$missing = array_unique(array_merge(...$missing));

if ($this->output->getVerbosity() >= $this->parseVerbosity(OutputInterface::VERBOSITY_VERBOSE)) {
$errOutput = $this->output->getErrorStyle();
Expand All @@ -87,13 +76,11 @@ public function handle(LostInTranslation $lit)
}
}

$keys = array_keys($reported);

if ($this->option('sorted')) {
sort($keys);
sort($missing);
}

foreach ($keys as $key) {
foreach ($missing as $key) {
$this->line(OutputFormatter::escape($key));
}
}
Expand All @@ -103,23 +90,38 @@ public function handle(LostInTranslation $lit)
*
* @param \Countable|array $totalSteps
* @param \Closure $callback
* @return \Symfony\Component\Console\Helper\ProgressBar
* @return array
*/
protected function trackProgress(Countable|array $totalSteps, Closure $callback)
{
$items = [];

if ($this->option('no-progress')) {
foreach ($totalSteps as $value) {
if (($item = $callback($value)) && $item !== null) {
$items[] = $item;
}
}

return $items;
}

$bar = $this->output->createProgressBar(count($totalSteps));

$bar->start();

foreach ($totalSteps as $value) {
$callback($value, $bar);
if (($item = $callback($value)) && $item !== null) {
$items[] = $item;
}

$bar->advance();
}

$bar->finish();
$bar->clear();

return $bar;
return $items;
}

/**
Expand All @@ -141,4 +143,29 @@ protected function resolveFirstArgs(LostInTranslation $lit, array $nodes): array
}
return array_unique($translationKeys);
}

/**
* @param \CodingSocks\LostInTranslation\LostInTranslation $lit
* @param string|null $locale
* @return \Closure
*/
protected function makeMissingTranslationFinderCallback(LostInTranslation $lit, string|null $locale): Closure
{
return function (SplFileInfo $file) use ($lit, $locale) {
$nodes = $lit->findInFile($file);

$translationKeys = $this->resolveFirstArgs($lit, $nodes);

$missing = [];

foreach ($translationKeys as $key) {
if (!Lang::has($key, $locale)) {
// TODO: find a better way to check uniqueness
$missing[] = $key;
}
}

return $missing;
};
}
}
13 changes: 12 additions & 1 deletion src/LostInTranslation.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,20 @@ public function findInFile(SplFileInfo $file): array

if ($this->isBladeFile($file)) {
$str = $this->compiler->compileString($str);

return $finder->find($str);
}

$found = [];
$nowdocFinder = new BladeNowdocFinder();

foreach ($nowdocFinder->find($str) as $node) {
$str = $this->compiler->compileString($node->value);

array_push($found, ...$finder->find($str));
}

return $finder->find($str);
return array_merge($found, $finder->find($str));
}

/**
Expand Down
1 change: 0 additions & 1 deletion src/TranslationFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ class TranslationFinder
private $printer;

/**
* @param \Illuminate\View\Compilers\BladeCompiler $compiler
* @param array $detect
* @param \PhpParser\Parser|null $parser
* @param \PhpParser\PrettyPrinter $printer
Expand Down
49 changes: 49 additions & 0 deletions tests/BladeNowdocFinderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace CodingSocks\LostInTranslation\Tests;

use CodingSocks\LostInTranslation\BladeNowdocFinder;
use CodingSocks\LostInTranslation\TranslationFinder;

class BladeNowdocFinderTest extends TestCase
{
public function testBladeDirective()
{
$str = <<<'EOD'
<?php
class ExampleObject
{
/**
* Create a new component instance.
*/
public function skip()
{
return <<<'eod'
<div>
<!-- This has to be undetected. -->
</div>
eod;
}
/**
* Get the view / contents that represent the component.
*/
public function keep(): string
{
return <<<'blade'
<div>
<!-- This has to be detected. -->
</div>
blade;
}
}
EOD;

$finder = new BladeNowdocFinder();

$nodes = $finder->find($str);

$this->assertCount(1, $nodes);
}
}

0 comments on commit fdcfa74

Please sign in to comment.