diff --git a/composer.json b/composer.json index af4dbb7..0734440 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "php": "^7", "gitonomy/gitlib": "~1.0", "symfony/console": "^3.3", - "code-lts/doctum": "^5.2.0" + "code-lts/doctum": "^5.3.1" }, "bin": [ "bin/docs" diff --git a/composer.lock b/composer.lock index 807f2a0..fdd1600 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "61174254efbdd16bc67daebf6d0e889c", + "content-hash": "e51ab6f585ce54c405f0ce66b61a582e", "packages": [ { "name": "code-lts/cli-tools", @@ -71,23 +71,23 @@ }, { "name": "code-lts/doctum", - "version": "v5.2.1", + "version": "v5.3.1", "source": { "type": "git", "url": "https://github.com/code-lts/doctum.git", - "reference": "213dd0099a35cfe05d9881e9bdfeb27fbd245a78" + "reference": "b7e2ffb5118ca961aa4ca380adb8bf4d5113ef98" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/code-lts/doctum/zipball/213dd0099a35cfe05d9881e9bdfeb27fbd245a78", - "reference": "213dd0099a35cfe05d9881e9bdfeb27fbd245a78", + "url": "https://api.github.com/repos/code-lts/doctum/zipball/b7e2ffb5118ca961aa4ca380adb8bf4d5113ef98", + "reference": "b7e2ffb5118ca961aa4ca380adb8bf4d5113ef98", "shasum": "" }, "require": { "code-lts/cli-tools": "^1.3.1", "michelf/php-markdown": "~1.3", "nikic/php-parser": "~4.6", - "php": "^7.1 || ^8.0", + "php": "^7.1.3 || ^8.0", "phpdocumentor/reflection-docblock": "~4.3|~5.2.1", "symfony/console": "~3.4|~4.3|~5.1|~5.2", "symfony/filesystem": "~3.4|~4.3|~5.1|~5.2", @@ -139,9 +139,9 @@ ], "support": { "issues": "https://github.com/code-lts/doctum/issues", - "source": "https://github.com/code-lts/doctum/tree/v5.2.1" + "source": "https://github.com/code-lts/doctum/tree/v5.3.1" }, - "time": "2020-11-30T21:07:21+00:00" + "time": "2020-12-30T13:09:42+00:00" }, { "name": "gitonomy/gitlib", diff --git a/conf/doctum.php b/conf/doctum.php index 21fdf84..9d8e07b 100644 --- a/conf/doctum.php +++ b/conf/doctum.php @@ -8,7 +8,7 @@ use SilverStripe\ApiDocs\Data\Config; use SilverStripe\ApiDocs\Inspections\RecipeFinder; use SilverStripe\ApiDocs\Inspections\RecipeVersionCollection; -use SilverStripe\ApiDocs\Twig\NavigationExtension; +use SilverStripe\ApiDocs\RemoteRepository\SilverStripeRemoteRepository; // Get config $config = Config::getConfig(); @@ -37,6 +37,8 @@ 'versions' => $versions, 'build_dir' => Config::configPath($config['paths']['www']) . '/%version%', 'cache_dir' => Config::configPath($config['paths']['cache']) . '/%version%', + 'source_dir' => $versions->getPackagePath(''),// Root of all the packages + 'remote_repository' => new SilverStripeRemoteRepository('', $versions->getPackagePath('') . '/'), 'template_dirs' => [ __DIR__ .'/themes' ], ]); @@ -57,15 +59,6 @@ return new \SilverStripe\ApiDocs\Renderer\SilverStripeRenderer($sc['twig'], $sc['themes'], $sc['tree'], $sc['indexer']); }; -// Override twig -/** @var Twig_Environment $twig */ -$twig = $doctum['twig']; -unset($doctum['twig']); -$doctum['twig'] = function () use ($twig) { - $twig->addExtension(new NavigationExtension()); - return $twig; -}; - // Override json store $store = $doctum['store']; unset($doctum['store']); diff --git a/src/Inspections/RecipeVersionCollection.php b/src/Inspections/RecipeVersionCollection.php index c9c165d..d40a077 100644 --- a/src/Inspections/RecipeVersionCollection.php +++ b/src/Inspections/RecipeVersionCollection.php @@ -137,9 +137,9 @@ protected function switchVersion(Version $version) * @param string $package * @return string */ - public function getPackagePath($package) + public function getPackagePath(string $package): string { - return Config::configPath($this->config['paths']['packages'] . '/' . $package); + return realpath(Config::configPath($this->config['paths']['packages'] . '/' . $package)); } /** diff --git a/src/Parser/SilverStripeNodeVisitor.php b/src/Parser/SilverStripeNodeVisitor.php index 60f5c11..b1aea75 100644 --- a/src/Parser/SilverStripeNodeVisitor.php +++ b/src/Parser/SilverStripeNodeVisitor.php @@ -2,11 +2,9 @@ namespace SilverStripe\ApiDocs\Parser; -use PhpParser\Node\Stmt\Class_ as ClassNode; use Doctum\Parser\NodeVisitor; use PhpParser\Node\Stmt\ClassLike as ClassLikeNode; use PhpParser\Node\Stmt\Property as PropertyNode; -use Doctum\Reflection\PropertyReflection; use SilverStripe\ApiDocs\Reflection\SilverStripeClassReflection; class SilverStripeNodeVisitor extends NodeVisitor @@ -14,60 +12,16 @@ class SilverStripeNodeVisitor extends NodeVisitor protected function addClassOrInterface(ClassLikeNode $node) { $class = new SilverStripeClassReflection((string) $node->namespacedName, $node->getLine()); - if ($node instanceof ClassNode) { - $class->setModifiers($node->flags); - } - $class->setNamespace($this->context->getNamespace()); - $class->setAliases($this->context->getAliases()); - $class->setHash($this->context->getHash()); - $class->setFile($this->context->getFile()); - - $comment = $this->context->getDocBlockParser()->parse($node->getDocComment(), $this->context, $class); - $class->setDocComment($node->getDocComment()); - $class->setShortDesc($comment->getShortDesc()); - $class->setLongDesc($comment->getLongDesc()); - if ($errors = $comment->getErrors()) { - $class->setErrors($errors); - } else { - $class->setTags($comment->getOtherTags()); - } - - if ($this->context->getFilter()->acceptClass($class)) { - if ($errors) { - $this->context->addErrors((string) $class, $node->getLine(), $errors); - } - $this->context->enterClass($class); - } - - return $class; + return $this->addClassOrInterfaceForReflection($class, $node); } protected function addProperty(PropertyNode $node) { foreach ($node->props as $prop) { - $property = new PropertyReflection($prop->name, $prop->getLine()); - $property->setModifiers($node->flags); - - $property->setDefault($prop->default); - - $comment = $this->context->getDocBlockParser()->parse($node->getDocComment(), $this->context, $property); - $property->setDocComment($node->getDocComment()); - $property->setShortDesc($comment->getShortDesc()); - $property->setLongDesc($comment->getLongDesc()); - if ($errors = $comment->getErrors()) { - $property->setErrors($errors); - } else { - $this->addTagFromCommentToMethod('var', $comment, $property, $errors); - - $property->setTags($comment->getOtherTags()); - } + [$property, $errors] = $this->getPropertyReflectionFromParserProperty($node, $prop); if ($this->context->getFilter()->acceptProperty($property)) { - if ($property->getTags('config')) { - $this->context->getClass()->addConfig($property); - } else { - $this->context->getClass()->addProperty($property); - } + $this->context->getClass()->addProperty($property); if ($errors) { $this->context->addErrors((string) $property, $prop->getLine(), $errors); diff --git a/src/Reflection/SilverStripeClassReflection.php b/src/Reflection/SilverStripeClassReflection.php index 2a2da64..cc330a0 100644 --- a/src/Reflection/SilverStripeClassReflection.php +++ b/src/Reflection/SilverStripeClassReflection.php @@ -7,24 +7,17 @@ class SilverStripeClassReflection extends ClassReflection { - const CATEGORY_CONFIG = 4; - - private static $categoryName = [ - 1 => 'class', - 2 => 'interface', - 3 => 'trait', - 4 => 'config', - ]; + /** @var array */ protected $configs = []; - public function addConfig(PropertyReflection $property) + public function addConfig(PropertyReflection $property): void { $this->configs[$property->getName()] = $property; $property->setClass($this); } - public function getConfigs() + public function getConfigs(): array { return $this->configs; } diff --git a/src/RemoteRepository/SilverStripeRemoteRepository.php b/src/RemoteRepository/SilverStripeRemoteRepository.php new file mode 100644 index 0000000..c6e36e6 --- /dev/null +++ b/src/RemoteRepository/SilverStripeRemoteRepository.php @@ -0,0 +1,39 @@ +localPath is the root path to packages + // Example: /mnt/Dev/@code-lts/@doctum-fork/api.silverstripe.org/data/packages/ + // $this->name is empty, and not used + // $relativePath for the current file + // Example "silverstripe/admin/code/AdminRootController.php" + $pathParts = explode('/', $relativePath, 3); + // Example: [silverstripe, admin, code/AdminRootController.php] + $this->name = $pathParts[0] . '/' . $pathParts[1]; + + $packageConfig = Config::getConfig()['packages'][$this->name]; + $rootPath = $packageConfig['repository']; + if (substr($rootPath, -4) === '.git') { + $rootPath = substr($rootPath, 0, -4); + } + if (isset($packageConfig['versionmap'])) { + $versionMaps = Config::getConfig()['versionmaps']; + $projectVersion = $versionMaps[$packageConfig['versionmap']][(string) $projectVersion] ?? $projectVersion; + } + $url = $rootPath . '/blob/' . $this->buildProjectPath($projectVersion, $pathParts[2]); + + if (null !== $line) { + $url .= '#L' . (int) $line; + } + + return $url; + } +} diff --git a/src/Renderer/SilverStripeRenderer.php b/src/Renderer/SilverStripeRenderer.php index b01d9a8..10b9929 100644 --- a/src/Renderer/SilverStripeRenderer.php +++ b/src/Renderer/SilverStripeRenderer.php @@ -2,7 +2,6 @@ namespace SilverStripe\ApiDocs\Renderer; -use Doctum\Message; use Doctum\Project; use Doctum\Renderer\Renderer; use SilverStripe\ApiDocs\Reflection\SilverStripeClassReflection; @@ -12,27 +11,13 @@ class SilverStripeRenderer extends Renderer protected function renderClassTemplates(array $classes, Project $project, $callback = null) { foreach ($classes as $class) { - if (null !== $callback) { - call_user_func( - $callback, - Message::RENDER_PROGRESS, - ['Class', $class->getName(), $this->step, $this->steps] - ); - } - - $properties = $class->getProperties($project->getConfig('include_parent_data')); + $variables = $this->getVariablesFromClassReflection($class, $project, $callback); - $sortProperties = $project->getConfig('sort_class_properties'); - if ($sortProperties) { - if (is_callable($sortProperties)) { - uksort($properties, $sortProperties); - } else { - ksort($properties); - } - } + $configs = []; if ($class instanceof SilverStripeClassReflection) { $configs = $class->getConfigs($project->getConfig('include_parent_data')); + $sortProperties = $project->getConfig('sort_class_properties'); if ($sortProperties) { if (is_callable($sortProperties)) { uksort($configs, $sortProperties); @@ -40,57 +25,9 @@ protected function renderClassTemplates(array $classes, Project $project, $callb ksort($properties); } } - } else { - $configs = array(); - } - - $methods = $class->getMethods($project->getConfig('include_parent_data')); - - $sortMethods = $project->getConfig('sort_class_methods'); - if ($sortMethods) { - if (is_callable($sortMethods)) { - uksort($methods, $sortMethods); - } else { - ksort($methods); - } - } - - $constants = $class->getConstants($project->getConfig('include_parent_data')); - - $sortConstants = $project->getConfig('sort_class_constants'); - if ($sortConstants) { - if (is_callable($sortConstants)) { - uksort($constants, $sortConstants); - } else { - ksort($constants); - } - } - - $traits = $class->getTraits($project->getConfig('include_parent_data')); - - $sortTraits = $project->getConfig('sort_class_traits'); - if ($sortTraits) { - if (is_callable($sortTraits)) { - uksort($traits, $sortTraits); - } else { - ksort($traits); - } - } - - $sortInterfaces = $project->getConfig('sort_class_interfaces'); - if ($sortInterfaces) { - $class->sortInterfaces($sortInterfaces); } - $variables = [ - 'class' => $class, - 'properties' => $properties, - 'configs' => $configs, - 'methods' => $methods, - 'constants' => $constants, - 'traits' => $traits, - 'tree' => $this->getTree($project), - ]; + $variables['configs'] = $configs; foreach ($this->theme->getTemplates('class') as $template => $target) { $this->save( @@ -102,14 +39,4 @@ protected function renderClassTemplates(array $classes, Project $project, $callb } } } - - private function getTree(Project $project) - { - $key = $project->getBuildDir(); - if (!isset($this->cachedTree[$key])) { - $this->cachedTree[$key] = $this->tree->getTree($project); - } - - return $this->cachedTree[$key]; - } } diff --git a/src/Twig/NavigationExtension.php b/src/Twig/NavigationExtension.php deleted file mode 100644 index f7a5677..0000000 --- a/src/Twig/NavigationExtension.php +++ /dev/null @@ -1,33 +0,0 @@ -navigation[$url])) { - $this->navigation[$url] = file_get_contents($url); - } - return $this->navigation[$url]; - } -} diff --git a/tests/SilverStripeRemoteRepositoryTest.php b/tests/SilverStripeRemoteRepositoryTest.php new file mode 100644 index 0000000..c7a23d8 --- /dev/null +++ b/tests/SilverStripeRemoteRepositoryTest.php @@ -0,0 +1,77 @@ +getFileUrl( + '4', + 'silverstripe/admin/code/AdminRootController.php', + 0 + ); + + $this->assertSame( + 'https://github.com/silverstripe/silverstripe-admin/blob/1/code/AdminRootController.php#L0', + $url + ); + + $url = $remoteRepo->getFileUrl( + '4', + 'silverstripe/graphql/src/Extensions/IntrospectionProvider.php', + 0 + ); + + $this->assertSame( + 'https://github.com/silverstripe/' + . 'silverstripe-graphql/blob/3/src/Extensions/IntrospectionProvider.php#L0', + $url + ); + + $url = $remoteRepo->getFileUrl( + 'master', + 'silverstripe/graphql/src/Extensions/IntrospectionProvider.php', + 0 + ); + + $this->assertSame( + 'https://github.com/silverstripe/' + . 'silverstripe-graphql/blob/master/src/Extensions/IntrospectionProvider.php#L0', + $url + ); + + $url = $remoteRepo->getFileUrl( + '3', + 'silverstripe/graphql/src/Extensions/IntrospectionProvider.php', + 0 + ); + + $this->assertSame( + 'https://github.com/silverstripe/' + . 'silverstripe-graphql/blob/3/src/Extensions/IntrospectionProvider.php#L0', + $url + ); + + // A mysterious version did pop out, oh snap + $url = $remoteRepo->getFileUrl( + 'foobar', + 'silverstripe/graphql/src/Extensions/IntrospectionProvider.php', + 0 + ); + + $this->assertSame( + 'https://github.com/silverstripe/' + . 'silverstripe-graphql/blob/foobar/src/Extensions/IntrospectionProvider.php#L0', + $url + ); + } +}