Skip to content

Commit fc36bcd

Browse files
authored
Merge pull request #96 from kasimi/lang-keys
Scan all array literals for language keys
2 parents 459aebd + f15dd7c commit fc36bcd

File tree

5 files changed

+97
-54
lines changed

5 files changed

+97
-54
lines changed

src/Tests/ArrayKeyVisitor.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
/**
3+
*
4+
* EPV :: The phpBB Forum Extension Pre Validator.
5+
*
6+
* @copyright (c) 2014 phpBB Limited <https://www.phpbb.com>
7+
* @license GNU General Public License, version 2 (GPL-2.0)
8+
*
9+
*/
10+
namespace Phpbb\Epv\Tests;
11+
12+
use PhpParser\Node;
13+
use PhpParser\Node\Expr\Array_;
14+
use PhpParser\Node\Expr\ArrayItem;
15+
use PhpParser\Node\Scalar\String_;
16+
use PhpParser\NodeVisitorAbstract;
17+
18+
class ArrayKeyVisitor extends NodeVisitorAbstract
19+
{
20+
/**
21+
* @var array
22+
*/
23+
private $keys;
24+
25+
/**
26+
* @param array $nodes
27+
* @return void|null|Node[]
28+
*/
29+
public function beforeTraverse(array $nodes)
30+
{
31+
$this->keys = [];
32+
}
33+
34+
/**
35+
* @param Node $node
36+
* @return void|null|int|Node
37+
*/
38+
public function enterNode(Node $node)
39+
{
40+
if ($node instanceof Array_)
41+
{
42+
foreach ($node->items as $item)
43+
{
44+
/** @var ArrayItem $item */
45+
if ($item->key instanceof String_)
46+
{
47+
$this->keys[] = $item->key->value;
48+
}
49+
}
50+
}
51+
}
52+
53+
/**
54+
* @return array
55+
*/
56+
public function get_array_keys()
57+
{
58+
return $this->keys;
59+
}
60+
}

src/Tests/Tests/epv_test_validate_languages.php

Lines changed: 20 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,30 @@
1212
namespace Phpbb\Epv\Tests\Tests;
1313

1414
use Phpbb\Epv\Output\OutputInterface;
15+
use Phpbb\Epv\Tests\ArrayKeyVisitor;
1516
use Phpbb\Epv\Tests\BaseTest;
1617
use PhpParser\Error;
17-
use PhpParser\Node\Expr\Array_;
18-
use PhpParser\Node\Expr\ArrayItem;
19-
use PhpParser\Node\Expr\Assign;
20-
use PhpParser\Node\Expr\FuncCall;
21-
use PhpParser\Node\Scalar\String_;
18+
use PhpParser\NodeTraverser;
2219
use PhpParser\Parser;
2320
use PhpParser\ParserFactory;
2421

2522
class epv_test_validate_languages extends BaseTest
2623
{
2724
/**
28-
* @var Parser
29-
*/
25+
* @var Parser
26+
*/
3027
private $parser;
3128

29+
/**
30+
* @var ArrayKeyVisitor
31+
*/
32+
private $visitor;
33+
34+
/**
35+
* @var NodeTraverser
36+
*/
37+
private $traverser;
38+
3239
/**
3340
* @param bool $debug if debug is enabled
3441
* @param OutputInterface $output
@@ -43,6 +50,9 @@ public function __construct($debug, OutputInterface $output, $basedir, $namespac
4350

4451
$this->directory = true;
4552
$this->parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
53+
$this->visitor = new ArrayKeyVisitor;
54+
$this->traverser = new NodeTraverser;
55+
$this->traverser->addVisitor($this->visitor);
4656
}
4757

4858
/**
@@ -99,8 +109,7 @@ public function validateDirectory(array $files)
99109
}
100110

101111
/**
102-
* This method scans through all global-scoped calls to array_merge
103-
* and extracts all string keys of all array arguments.
112+
* This method scans through all array literals and collects all their string keys.
104113
*
105114
* @param string $filename File name to a phpBB language file
106115
* @return array
@@ -109,50 +118,9 @@ public function validateDirectory(array $files)
109118
protected function load_language_keys($filename)
110119
{
111120
$contents = @file_get_contents($filename);
112-
113-
$keys = [];
114-
115121
$nodes = $this->parser->parse($contents);
116-
117-
foreach ($nodes as $node)
118-
{
119-
if ($node instanceof Assign && $node->expr instanceof FuncCall)
120-
{
121-
/** @var FuncCall $expr */
122-
$expr = $node->expr;
123-
124-
if ($expr->name->getFirst() === 'array_merge')
125-
{
126-
for ($i = 1; $i < sizeof($expr->args); $i++)
127-
{
128-
/** @var Array_ $array */
129-
$array = $expr->args[$i]->value;
130-
131-
if ($array instanceof Array_)
132-
{
133-
foreach ($array->items as $item)
134-
{
135-
/** @var ArrayItem $item */
136-
if ($item->key instanceof String_)
137-
{
138-
$keys[] = $item->key->value;
139-
}
140-
else
141-
{
142-
$this->output->addMessage(OutputInterface::NOTICE, 'Language key is not a string value in ' . substr($filename, strlen($this->basedir)) . ' on line ' . $item->key->getLine());
143-
}
144-
}
145-
}
146-
else
147-
{
148-
$this->output->addMessage(OutputInterface::ERROR, sprintf('Expected argument %d of array_merge() to be %s, got %s on line %d', $i + 1, Array_::class, get_class($array), $array->getLine()));
149-
}
150-
}
151-
}
152-
}
153-
}
154-
155-
return $keys;
122+
$this->traverser->traverse($nodes);
123+
return $this->visitor->get_array_keys();
156124
}
157125

158126
/**

tests/testFiles/language/en/common.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@
1313
$lang = array_merge($lang, array(
1414
'A' => 'First language string',
1515
'B' => 'Second language string',
16+
'C' => [
17+
1 => 'Singular',
18+
2 => 'Plural',
19+
],
1620
));

tests/testFiles/language/en_complete/common.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
'A' => 'First language string',
1515
));
1616

17-
$lang = array_merge($lang, array(
17+
$b = array(
1818
'B' => 'Second language string',
19-
));
19+
);
20+
21+
$lang = array_merge($lang, $b, [
22+
'C' => [
23+
// Missing plural should not generate an error
24+
1 => 'Singular',
25+
],
26+
]);

tests/testFiles/language/en_incomplete/common.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,8 @@
1212

1313
$lang = array_merge($lang, array(
1414
'A' => 'First language string',
15+
'C' => [
16+
1 => 'Singular',
17+
2 => 'Plural',
18+
],
1519
));

0 commit comments

Comments
 (0)