#!/usr/bin/env php * * This source file is subject to the license that is bundled * with this source code in the file LICENSE */ function recursiveRemoveDirectory($directory) { foreach (glob("{$directory}/*") as $file) { if (is_dir($file)) { recursiveRemoveDirectory($file); } else { unlink($file); } } rmdir($directory); } $path = __DIR__.'/../src/Model'; try { recursiveRemoveDirectory($path); } catch (\Exception $e) { } mkdir($path, 02775, true); $path = realpath($path); require __DIR__.'/../vendor/autoload.php'; use gossi\codegen\generator\CodeGenerator; use gossi\codegen\model\PhpClass; use gossi\codegen\model\PhpMethod; use gossi\codegen\model\PhpProperty; use Symfony\Component\Console\Application; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; $loader = new Twig_Loader_Filesystem(__DIR__.'/../src/Resources/'); $twig = new Twig_Environment($loader, ['debug' => true]); $twig->addExtension(new Twig_Extension_Debug()); $license = <<register('buildModelClasses') ->addArgument('version', InputArgument::REQUIRED, 'Version to build') ->setCode( function (InputInterface $input, OutputInterface $output) use ($twig, $license, $path) { $style = new \Symfony\Component\Console\Style\SymfonyStyle($input, $output); $style->title("Building Model Classes for: ".$input->getArgument('version')); $definition = \GuzzleHttp\json_decode( file_get_contents( __DIR__.'/../src/Resources/service_description-v'.$input->getArgument('version').'.json' ), true ); $generator = new CodeGenerator(); foreach ($definition['models'] as $resource => $models) { foreach ($models as $name => $model) { $resource = str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $resource))); $name = str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $name))); $class = new PhpClass(); $class->setQualifiedName('RestCord\\Model\\'.ucwords($resource).'\\'.ucwords($name)); $class->setDescription(ucwords($name)." Model"); $class->setProperties( array_map( function (&$name, $property) use ($class, $resource, $model) { $optional = strpos($name, '?') !== false; $name = lcfirst(str_replace([' ', '?'], '', str_replace('-', '_', $name))); $prop = new PhpProperty($name); $prop->setType(normalizeType($name, $resource, $property).($optional ? "|null" : "")); $prop->setDescription($property['description']); if (isset($property['default'])) { $prop->setValue($property['default']); } return $prop; }, array_keys($model['properties']), $model['properties'] ) ); addTraits($class, $resource, $name); $constructor = new PhpMethod('__construct'); $constructor->addSimpleParameter('content', 'array', null); $constructor->setBody( << \$value) { \$key = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', \$key)))); if (property_exists(\$this, \$key)) { \$this->{\$key} = \$value; } } EOF ); $constructor->setVisibility('public'); $class->setMethod($constructor); @mkdir($path.'/'.ucwords($resource), 02775, true); file_put_contents( $path.'/'.ucwords($resource).'/'.ucwords($name).'.php', $license.$generator->generate($class) ); } } $style->success('Finished. Classes built in: '.realpath($path)); } ) ->getApplication() ->setDefaultCommand('buildModelClasses', true) ->run(); function normalizeType(string $name, string $resource, array $property): string { $type = $property['type']; if ($name === 'user' && $resource === 'Guild') { $type = "user/user"; } switch ($type) { default: if (strpos($type, '/') !== false || strpos($type, 'Array<') === 0) { $array = false; if (stripos($type, 'Array') !== false) { $array = true; $type = str_replace(['Array<', '>'], '', $type); } if ($type === 'snowflake') { return 'int[]'; } $cls = "\\RestCord\\Model\\"; $tmp = explode('/', $type); $cls .= ucwords($tmp[0])."\\"; $clean = str_replace(['-object', '-'], ['', ' '], $tmp[1]); $clean = ucwords($clean); $clean = str_replace(' ', '', $clean); $fullClass = $cls.$clean.($array ? '[]' : ''); $fullClass = mapBadDocs($fullClass); return $fullClass; } return $type; case 'array': if (strpos($property['description'], "ids") !== false) { return "int[]"; } return "array"; case 'ISO8601 timestamp': case 'ISO8601': return '\DateTimeImmutable'; case 'datetime': return '\DateTime'; case 'snowflake': case 'integer': case 'timestamp': return 'int'; case 'object': return 'array'; case 'boolean': return 'bool'; } } function isTransformType(string $type): bool { $nonTransform = ['string', 'array']; return array_search($type, $nonTransform) === false; } function mapBadDocs(string $cls): string { switch ($cls) { case '\RestCord\Model\User\DmChannel': return '\RestCord\Model\Channel\DmChannel'; case '\RestCord\Model\Channel\Invite': case '\RestCord\Model\Guild\Invite': return '\RestCord\Model\Invite\Invite'; case '\RestCord\Model\Guild\GuildChannel': return '\RestCord\Model\Channel\GuildChannel'; case '\RestCord\Model\Guild\User': case '\RestCord\Model\Channel\User': return '\RestCord\Model\User\User'; case 'ISO8601': case '\RestCord\Model\Channel\ISO8601': return '\DateTimeImmutable'; default: return $cls; } return $cls; } function addTraits(PhpClass $class, string $resource, string $name) { if ($resource === 'User' && $name === 'User') { $class->addUseStatement(\RestCord\Traits\AvatarTrait::class)->addTrait("AvatarTrait"); } if ($resource === 'Guild' && $name === 'Guild') { $class->addUseStatement(\RestCord\Traits\IconTrait::class)->addTrait("IconTrait"); $class->addUseStatement(\RestCord\Traits\SplashTrait::class)->addTrait("SplashTrait"); } }