Skip to content

Instantly share code, notes, and snippets.

@chx
Last active April 22, 2024 00:24
Show Gist options
  • Save chx/6a0f512f1465d5f5720f100c16ea26db to your computer and use it in GitHub Desktop.
Save chx/6a0f512f1465d5f5720f100c16ea26db to your computer and use it in GitHub Desktop.
<?php
use Drupal\Component\Serialization\Yaml;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Use_;
use PhpParser\NodeFinder;
use PhpParser\ParserFactory;
use Symfony\Component\DependencyInjection\Container;
require_once 'autoload.php';
$it = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator('core'));
foreach ($it as $fileinfo) {
assert($fileinfo instanceof \SplFileInfo);
$filename = $fileinfo->getFilename();
$full_path = $fileinfo->getPathname();
if (str_ends_with($filename, '.info.yml')) {
$info = Yaml::decode(file_get_contents($full_path));
if ($info['type'] === 'module') {
$dir = dirname($full_path);
$module_dirs[$dir] = [
'name' => basename($filename, '.info.yml'),
'length' => strlen($dir),
];
}
}
if (str_ends_with($filename, '.module') || str_ends_with($filename, '.inc')) {
$files[] = $full_path;
}
}
// Longer ones first.
uasort($module_dirs, fn ($a, $b) => $b['length'] - $a['length']);
$preg = '#^(' . implode('|', array_keys($module_dirs)) . ')#';
$parser = (new ParserFactory())->createForHostVersion();
$finder = new NodeFinder();
$files = ['core/modules/user/user.module'];
foreach ($files as $file) {
// The includes/ dir and test fixture.
if (!preg_match($preg, $file, $matches)) {
continue;
}
$module = $module_dirs[$matches[1]]['name'];
@mkdir($matches[1] . '/src');
$outdir = $matches[1] . '/src/Hook/';
@mkdir($outdir);
$class = Container::camelize($module) . 'Hooks';
$outfile = "$outdir/$class.php";
$outlines = [
'<?php',
'',
"namespace Drupal\\$module\\Hook;",
'',
'use Drupal\\Core\\Extension\\Hook;'
];
$code = file_get_contents($file);
$lines = explode("\n", $code);
$stmts = $parser->parse($code);
if ($uses = $finder->findInstanceOf($stmts, Use_::class)) {
foreach ($uses as $use) {
for ($i = $use->getStartLine(); $i <= $use->getEndLine(); $i++) {
$outlines[] = $lines[$i - 1];
}
}
}
$outlines[] = "class $class {";
$functions = $finder->findInstanceOf($stmts, Function_::class);
foreach ($functions as $function) {
assert($function instanceof Function_);
if (!preg_match('/^ \* Implements hook_/m', $function->getDocComment())) {
continue;
}
$function_name = $function->name;
if (!str_starts_with($function_name, $module . '_')) {
continue;
}
$hook = substr($function_name, strlen($module) + 1);
for ($i = $function->getDocComment()->getStartLine(); $i <= $function->getDocComment()->getEndLine(); $i++) {
unset($lines[$i - 1]);
}
$outlines[] = " #[Hook(hook: '$hook')]";
for ($i = $function->getStartLine(); $i <= $function->getEndLine(); $i++) {
$outlines[] = ' ' . preg_replace("/^function $function_name/", 'public function ' . lcfirst(Container::camelize($hook)), $lines[$i - 1]);
unset($lines[$i - 1]);
}
}
$outlines[] = '}';
file_put_contents($file, implode("\n", $lines));
file_put_contents($outfile, implode("\n", $outlines));
}
// You need to run composer phpcbf on the converted file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment