Skip to content

Commit

Permalink
feat: use ast visitors to detect icon annotations and functions
Browse files Browse the repository at this point in the history
  • Loading branch information
yassinedoghri committed Apr 9, 2024
1 parent 7601070 commit d3713f7
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 26 deletions.
33 changes: 8 additions & 25 deletions src/Console/Commands/ScanCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,13 @@
use Exception;
use PHPIcons\Config\PHPIconsConfig;
use PHPIcons\Config\PHPIconsConfigBuilder;
use PHPIcons\Console\Icon;
use PHPIcons\Console\IconData;
use PHPIcons\Console\IconSet;
use PHPIcons\Console\Visitors\IconsAnnotationsVisitor;
use PHPIcons\Console\Visitors\IconsFunctionsVisitor;
use PHPIcons\Icons;
use PhpParser\Error;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\String_;
use PhpParser\NodeFinder;
use PhpParser\NodeTraverser;
use PhpParser\ParserFactory;

/**
Expand Down Expand Up @@ -247,23 +242,11 @@ private function extractIconsFromPHPFile(string $filePath): void
return;
}

$nodeFinder = new NodeFinder();
/** @var (FuncCall|MethodCall)[] */
$nodes = $nodeFinder->find(
$ast,
fn (Node $node) => ($node instanceof FuncCall || $node instanceof MethodCall)
&& ($node->name instanceof Name || $node->name instanceof Identifier)
&& in_array($node->name->toString(), $this->config->getIdentifiers(), true)
&& $node->getArgs() !== [] && $node->getArgs()[0]->value instanceof String_
);

foreach ($nodes as $node) {
/** @var String_ $strNode */
$strNode = $node->getArgs()[0]
->value;

$this->iconData->addIcon(new Icon($filePath, $strNode, $this->config->getDefaultPrefix()));
}
$traverser = new NodeTraverser();
$traverser->addVisitor(new IconsFunctionsVisitor($filePath, $this->iconData, $this->config));
$traverser->addVisitor(new IconsAnnotationsVisitor($filePath, $this->iconData, $this->config));

$traverser->traverse($ast);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Console/IconNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function getColumnNumber(): int
throw new \RuntimeException('Invalid position information');
}

$lineStartPos = strrpos($code, "\n", $filePosition - strlen($code));
$lineStartPos = strrpos($code, PHP_EOL, $filePosition - strlen($code));
if ($lineStartPos === false) {
$lineStartPos = -1;
}
Expand Down
77 changes: 77 additions & 0 deletions src/Console/Visitors/IconsAnnotationsVisitor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

namespace PHPIcons\Console\Visitors;

use PHPIcons\Config\PHPIconsConfig;
use PHPIcons\Console\Icon;
use PHPIcons\Console\IconData;
use PhpParser\Comment;
use PhpParser\Comment\Doc;
use PhpParser\Node;
use PhpParser\Node\Scalar\String_;
use PhpParser\NodeVisitorAbstract;

class IconsAnnotationsVisitor extends NodeVisitorAbstract
{
/**
* @var array<Doc|Comment>
*/
public array $comments = [];

public function __construct(
private readonly string $filePath,
private readonly IconData $iconData,
private readonly PHPIconsConfig $config
) {
}

public function enterNode(Node $node)
{
foreach ($node->getComments() as $nodeComment) {
if (! in_array($nodeComment, $this->comments)) {
$this->comments = [...$this->comments, $nodeComment];
}
}

return null;
}

public function afterTraverse(array $nodes)
{
foreach ($this->comments as $commentNode) {
// parse comment to get icon keys
$matched = preg_match_all(
"/@icon\s*\(\s*([\'\"])(?<iconKey>[a-z0-9\-\:]+)\\1\s*\)/",
$commentNode->getText(),
$matches,
PREG_OFFSET_CAPTURE
);

if (! $matched) {
continue;
}

foreach ($matches['iconKey'] as $iconKeyMatch) {
$startFilePosition = $commentNode->getStartFilePos() + $iconKeyMatch[1];
$line = substr_count(substr($commentNode->getText(), 0, $iconKeyMatch[1]), PHP_EOL);
$this->iconData->addIcon(
new Icon(
$this->filePath,
new String_(
$iconKeyMatch[0],
[
'startLine' => $commentNode->getStartLine() + $line,
'endLine' => $commentNode->getStartLine() + $line,
'startFilePos' => $startFilePosition,
'endFilePos' => $startFilePosition + strlen($iconKeyMatch[0]),
]
),
$this->config->getDefaultPrefix()
)
);
}
}

return null;
}
}
42 changes: 42 additions & 0 deletions src/Console/Visitors/IconsFunctionsVisitor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace PHPIcons\Console\Visitors;

use PHPIcons\Config\PHPIconsConfig;
use PHPIcons\Console\Icon;
use PHPIcons\Console\IconData;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\String_;
use PhpParser\NodeVisitorAbstract;

class IconsFunctionsVisitor extends NodeVisitorAbstract
{
public function __construct(
private readonly string $filePath,
private readonly IconData $iconData,
private readonly PHPIconsConfig $config
) {
}

public function enterNode(Node $node)
{
if (
($node instanceof FuncCall || $node instanceof MethodCall)
&& ($node->name instanceof Name || $node->name instanceof Identifier)
&& in_array($node->name->toString(), $this->config->getIdentifiers(), true)
&& $node->getArgs() !== [] && $node->getArgs()[0]->value instanceof String_
) {
/** @var String_ $strNode */
$strNode = $node->getArgs()[0]
->value;

$this->iconData->addIcon(new Icon($this->filePath, $strNode, $this->config->getDefaultPrefix()));
}

return null;
}
}

0 comments on commit d3713f7

Please sign in to comment.