Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functions scanner for Twig AST #59

Closed
wants to merge 1 commit into from
Closed
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
71 changes: 71 additions & 0 deletions src/RobustTwigFunctionsScanner.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace WP_CLI\I18n;

use Gettext\Utils\FunctionsScanner;

/**
* This is a function scanner for Twig templates. The initial string (whether template text or filename) is parsed.
* Then getFunctions() recursively traverses nodes.
* Nodes expressing a function call to one of the WordPress i18n functions (see parent {$this->functions) and saveGettextFunctions())
* are extracted.
*/
final class RobustTwigFunctionsScanner extends PhpFunctionsScanner {
public function __construct( $string, $twig, $func_names ) {
$this->tokens = $twig->parse( $twig->tokenize( new \Twig_Source( $string, '' ) ) );
$this->functions = $func_names;
}

/**
* A pseudo-generator to extract twig nodes corresponding to i18n function calls.
* @param array $constants Unused yet.
* @return array List of functions arguments/line-number compatible with PhpFunctionsScanner.
*/
public function getFunctions( array $constants = [] ) {
return self::_get_gettext_functions( $this->tokens );
}

private function is_gettext_function( $obj ) {
return ( $obj instanceof \Twig_Node_Expression_Function && in_array( $obj->getAttribute( 'name' ), $this->functions, TRUE ) );
}

private function _get_gettext_functions( $tokens ) {
if ( is_array( $tokens ) ) {
$functions = [];
foreach($tokens as $v) {
$functions = array_merge( $functions, self::_get_gettext_functions( $v ) );
}
return $functions;
}

$value = $tokens;
if ( $this->is_gettext_function( $value )) {
$arguments_obj = (array)$value->getNode( 'arguments' )->getIterator();
$name = $value->getAttribute('name');
$line = $value->getTemplateLine();

// basic verification of node arguments
if ( ! ( $arguments_obj[0] instanceof \Twig_Node_Expression_Constant && $arguments_obj[1] instanceof \Twig_Node_Expression_Constant ) ) {
\WP_CLI::warning( "Translation expression does not contains constant expressions " . PHP_EOL );
printf( STDERR, print_r( $arguments_obj, TRUE ) );
return [];
}

$arguments = array_map( function( $obj ) use( $name ) {
if ($name == '_n' && $obj instanceof \Twig_Node_Expression_GetAttr) {
return "count";
} else {
return $obj->getAttribute('value');
}
}, $arguments_obj );

return [ [ $name, $line, $arguments ] ];
}

$functions = [];
foreach( $tokens->getIterator() as $v) {
$functions = array_merge( $functions, self::_get_gettext_functions( $v ) );
}
return $functions;
}
}