Skip to content

Commit

Permalink
Merge pull request #56 from ADmad/extract-command
Browse files Browse the repository at this point in the history
Remove unneeded method overriding.
  • Loading branch information
ADmad authored Feb 13, 2021
2 parents 8f7e9eb + 0c953d9 commit df368b6
Show file tree
Hide file tree
Showing 2 changed files with 0 additions and 301 deletions.
10 changes: 0 additions & 10 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,3 @@ parameters:
- tests/bootstrap.php
paths:
- src
ignoreErrors:
-
message: "#^Parameter \\#1 \\$var_array of function extract is passed by reference, so it expects variables only\\.$#"
count: 1
path: src/Command/I18nExtractCommand.php

-
message: "#^Strict comparison using \\!\\=\\= between null and null will always evaluate to false\\.$#"
count: 2
path: src/Command/I18nExtractCommand.php
291 changes: 0 additions & 291 deletions src/Command/I18nExtractCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use Cake\Core\App;
use Cake\Core\Configure;
use Cake\Core\Plugin;
use Cake\Filesystem\Filesystem;
use Cake\Utility\Hash;
use Cake\Utility\Inflector;

Expand Down Expand Up @@ -335,294 +334,4 @@ public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionPar

return $parser;
}

/**
* Extract tokens out of all files to be processed
*
* @param \Cake\Console\Arguments $args The io instance
* @param \Cake\Console\ConsoleIo $io The io instance
* @return void
*/
protected function _extractTokens(Arguments $args, ConsoleIo $io): void
{
/** @var \Cake\Shell\Helper\ProgressHelper $progress */
$progress = $io->helper('progress');
$progress->init(['total' => count($this->_files)]);
$isVerbose = $args->getOption('verbose');

$functions = [
'__' => ['singular'],
'__n' => ['singular', 'plural'],
'__d' => ['domain', 'singular'],
'__dn' => ['domain', 'singular', 'plural'],
'__x' => ['context', 'singular'],
'__xn' => ['context', 'singular', 'plural'],
'__dx' => ['domain', 'context', 'singular'],
'__dxn' => ['domain', 'context', 'singular', 'plural'],
];
$pattern = '/(' . implode('|', array_keys($functions)) . ')\s*\(/';

foreach ($this->_files as $file) {
$this->_file = $file;
if ($isVerbose) {
$io->verbose(sprintf('Processing %s...', $file));
}

$code = file_get_contents($file);

if (preg_match($pattern, $code) === 1) {
$allTokens = token_get_all($code);

$this->_tokens = [];
foreach ($allTokens as $token) {
if (!is_array($token) || ($token[0] !== T_WHITESPACE && $token[0] !== T_INLINE_HTML)) {
$this->_tokens[] = $token;
}
}
unset($allTokens);

foreach ($functions as $functionName => $map) {
$this->_parse($io, $functionName, $map);
}
}

if (!$isVerbose) {
$progress->increment(1);
$progress->draw();
}
}
}

/**
* Parse tokens
*
* @param \Cake\Console\ConsoleIo $io The io instance
* @param string $functionName Function name that indicates translatable string (e.g: '__')
* @param array $map Array containing what variables it will find (e.g: domain, singular, plural)
* @return void
*/
protected function _parse(ConsoleIo $io, string $functionName, array $map): void
{
$count = 0;
$tokenCount = count($this->_tokens);

while ($tokenCount - $count > 1) {
$countToken = $this->_tokens[$count];
$firstParenthesis = $this->_tokens[$count + 1];
if (!is_array($countToken)) {
$count++;
continue;
}

[$type, $string, $line] = $countToken;
if (($type === T_STRING) && ($string === $functionName) && ($firstParenthesis === '(')) {
$position = $count;
$depth = 0;

while (!$depth) {
if ($this->_tokens[$position] === '(') {
$depth++;
} elseif ($this->_tokens[$position] === ')') {
$depth--;
}
$position++;
}

$mapCount = count($map);
$strings = $this->_getStrings($position, $mapCount);

if ($mapCount === count($strings)) {
$singular = '';
$plural = $context = null;
extract(array_combine($map, $strings));
$domain = $domain ?? 'default';
$details = [
'file' => $this->_file,
'line' => $line,
];
if ($this->_relativePaths) {
$details['file'] = '.' . str_replace(ROOT, '', $details['file']);
}
if ($plural !== null) {
$details['msgid_plural'] = $plural;
}
if ($context !== null) {
$details['msgctxt'] = $context;
}
$this->_addTranslation($domain, $singular, $details);
} else {
$this->_markerError($io, $this->_file, $line, $functionName, $count);
}
}
$count++;
}
}

/**
* Get the strings from the position forward
*
* @param int $position Actual position on tokens array
* @param int $target Number of strings to extract
* @return array Strings extracted
*/
protected function _getStrings(int &$position, int $target): array
{
$strings = [];
$count = count($strings);
while (
$count < $target
&& ($this->_tokens[$position] === ','
|| $this->_tokens[$position][0] === T_CONSTANT_ENCAPSED_STRING
|| $this->_tokens[$position][0] === T_LNUMBER
)
) {
$count = count($strings);
if ($this->_tokens[$position][0] === T_CONSTANT_ENCAPSED_STRING && $this->_tokens[$position + 1] === '.') {
$string = '';
while (
$this->_tokens[$position][0] === T_CONSTANT_ENCAPSED_STRING
|| $this->_tokens[$position] === '.'
) {
if ($this->_tokens[$position][0] === T_CONSTANT_ENCAPSED_STRING) {
$string .= $this->_formatString($this->_tokens[$position][1]);
}
$position++;
}
$strings[] = $string;
} elseif ($this->_tokens[$position][0] === T_CONSTANT_ENCAPSED_STRING) {
$strings[] = $this->_formatString($this->_tokens[$position][1]);
} elseif ($this->_tokens[$position][0] === T_LNUMBER) {
$strings[] = $this->_tokens[$position][1];
}
$position++;
}

return $strings;
}

/**
* Format a string to be added as a translatable string
*
* @param string $string String to format
* @return string Formatted string
*/
protected function _formatString(string $string): string
{
$quote = substr($string, 0, 1);
$string = substr($string, 1, -1);
if ($quote === '"') {
$string = stripcslashes($string);
} else {
$string = strtr($string, ["\\'" => "'", '\\\\' => '\\']);
}
$string = str_replace("\r\n", "\n", $string);

return addcslashes($string, "\0..\37\\\"");
}

/**
* Indicate an invalid marker on a processed file
*
* @param \Cake\Console\ConsoleIo $io The io instance.
* @param string $file File where invalid marker resides
* @param int $line Line number
* @param string $marker Marker found
* @param int $count Count
* @return void
*/
protected function _markerError($io, string $file, int $line, string $marker, int $count): void
{
if (strpos($this->_file, CAKE_CORE_INCLUDE_PATH) === false) {
$this->_countMarkerError++;
}

if (!$this->_markerError) {
return;
}

$io->err(sprintf("Invalid marker content in %s:%s\n* %s(", $file, $line, $marker));
$count += 2;
$tokenCount = count($this->_tokens);
$parenthesis = 1;

while (($tokenCount - $count > 0) && $parenthesis) {
if (is_array($this->_tokens[$count])) {
$io->err($this->_tokens[$count][1], 0);
} else {
$io->err($this->_tokens[$count], 0);
if ($this->_tokens[$count] === '(') {
$parenthesis++;
}

if ($this->_tokens[$count] === ')') {
$parenthesis--;
}
}
$count++;
}
$io->err("\n");
}

/**
* Search files that may contain translatable strings
*
* @return void
*/
protected function _searchFiles(): void
{
$pattern = false;
if (!empty($this->_exclude)) {
$exclude = [];
foreach ($this->_exclude as $e) {
if (DIRECTORY_SEPARATOR !== '\\' && $e[0] !== DIRECTORY_SEPARATOR) {
$e = DIRECTORY_SEPARATOR . $e;
}
$exclude[] = preg_quote($e, '/');
}
$pattern = '/' . implode('|', $exclude) . '/';
}

foreach ($this->_paths as $path) {
$path = realpath($path) . DIRECTORY_SEPARATOR;
/** @psalm-suppress InternalClass */
$fs = new Filesystem();
/** @psalm-suppress InternalMethod */
$files = $fs->findRecursive($path, '/\.php$/');
$files = array_keys(iterator_to_array($files));
sort($files);
if (!empty($pattern)) {
$files = preg_grep($pattern, $files, PREG_GREP_INVERT);
$files = array_values($files);
}
$this->_files = array_merge($this->_files, $files);
}
$this->_files = array_unique($this->_files);
}

/**
* Returns whether this execution is meant to extract string only from directories in folder represented by the
* APP constant, i.e. this task is extracting strings from same application.
*
* @return bool
*/
protected function _isExtractingApp(): bool
{
/** @psalm-suppress UndefinedConstant */
return $this->_paths === [APP];
}

/**
* Checks whether or not a given path is usable for writing.
*
* @param string $path Path to folder
* @return bool true if it exists and is writable, false otherwise
*/
protected function _isPathUsable($path): bool
{
if (!is_dir($path)) {
mkdir($path, 0770, true);
}

return is_dir($path) && is_writable($path);
}
}

0 comments on commit df368b6

Please sign in to comment.