From c9e27a0fa3c9e6a8e0a49d57c4304d59d58188b4 Mon Sep 17 00:00:00 2001 From: "lina.wolf" Date: Thu, 3 Oct 2024 09:22:15 +0200 Subject: [PATCH] [FEATURE] Add option to create an automatic menu For now all Document entries are added to the root document entry. In a follow up I plan to create a nested menu as well References #1108 --- .../guides-cli/resources/schema/guides.xsd | 1 + .../src/Markdown/MarkupLanguageParser.php | 9 +- .../src/Compiler/Passes/AutomaticMenuPass.php | 63 +++++++++ .../src/Compiler/Passes/GlobalMenuPass.php | 17 +++ .../Compiler/Passes/ToctreeValidationPass.php | 11 ++ .../DependencyInjection/GuidesExtension.php | 5 + .../guides/src/Settings/ProjectSettings.php | 13 ++ .../default-menu-md/expected/anotherPage.html | 35 ++++- .../default-menu-md/expected/index.html | 35 ++++- .../default-menu-md/expected/somePage.html | 35 ++++- .../default-menu-md/input/guides.xml | 1 + .../nested-menu-md/expected/dir2/index.html | 121 +++++++++++++++++ .../expected/dir2/somePage.html | 125 ++++++++++++++++++ .../nested-menu-md/expected/index.html | 124 +++++++++++++++++ .../nested-menu-md/input/anotherPage.md | 3 + .../nested-menu-md/input/dir1/index.md | 3 + .../nested-menu-md/input/dir2/index.md | 3 + .../nested-menu-md/input/dir2/somePage.md | 4 + .../nested-menu-md/input/guides.xml | 11 ++ .../nested-menu-md/input/index.md | 3 + .../markdown-full/nested-menu-md/input/skip | 1 + .../nested-menu-md/input/somePage.md | 4 + .../nested-menu-md/input/yetAnotherPage.md | 3 + 23 files changed, 623 insertions(+), 7 deletions(-) create mode 100644 packages/guides/src/Compiler/Passes/AutomaticMenuPass.php create mode 100644 tests/Integration/tests-full/markdown-full/nested-menu-md/expected/dir2/index.html create mode 100644 tests/Integration/tests-full/markdown-full/nested-menu-md/expected/dir2/somePage.html create mode 100644 tests/Integration/tests-full/markdown-full/nested-menu-md/expected/index.html create mode 100644 tests/Integration/tests-full/markdown-full/nested-menu-md/input/anotherPage.md create mode 100644 tests/Integration/tests-full/markdown-full/nested-menu-md/input/dir1/index.md create mode 100644 tests/Integration/tests-full/markdown-full/nested-menu-md/input/dir2/index.md create mode 100644 tests/Integration/tests-full/markdown-full/nested-menu-md/input/dir2/somePage.md create mode 100644 tests/Integration/tests-full/markdown-full/nested-menu-md/input/guides.xml create mode 100644 tests/Integration/tests-full/markdown-full/nested-menu-md/input/index.md create mode 100644 tests/Integration/tests-full/markdown-full/nested-menu-md/input/skip create mode 100644 tests/Integration/tests-full/markdown-full/nested-menu-md/input/somePage.md create mode 100644 tests/Integration/tests-full/markdown-full/nested-menu-md/input/yetAnotherPage.md diff --git a/packages/guides-cli/resources/schema/guides.xsd b/packages/guides-cli/resources/schema/guides.xsd index c25cc6f6a..1bb692b82 100644 --- a/packages/guides-cli/resources/schema/guides.xsd +++ b/packages/guides-cli/resources/schema/guides.xsd @@ -31,6 +31,7 @@ + diff --git a/packages/guides-markdown/src/Markdown/MarkupLanguageParser.php b/packages/guides-markdown/src/Markdown/MarkupLanguageParser.php index 0a56ac918..e92b8ee1d 100644 --- a/packages/guides-markdown/src/Markdown/MarkupLanguageParser.php +++ b/packages/guides-markdown/src/Markdown/MarkupLanguageParser.php @@ -24,6 +24,8 @@ use phpDocumentor\Guides\Nodes\DocumentNode; use phpDocumentor\Guides\Nodes\Node; use phpDocumentor\Guides\ParserContext; +use phpDocumentor\Guides\Settings\ProjectSettings; +use phpDocumentor\Guides\Settings\SettingsManager; use Psr\Log\LoggerInterface; use RuntimeException; @@ -40,16 +42,21 @@ final class MarkupLanguageParser implements MarkupLanguageParserInterface private DocumentNode|null $document = null; + private SettingsManager $settingsManager; + /** @param iterable> $parsers */ public function __construct( private readonly LoggerInterface $logger, private readonly iterable $parsers, + SettingsManager|null $settingsManager, ) { $cmEnvironment = new CommonMarkEnvironment(['html_input' => 'strip']); $cmEnvironment->addExtension(new CommonMarkCoreExtension()); $cmEnvironment->addExtension(new TableExtension()); $cmEnvironment->addExtension(new AutolinkExtension()); $this->markdownParser = new MarkdownParser($cmEnvironment); + // if for backward compatibility reasons no settings manager was passed, use the defaults + $this->settingsManager = $settingsManager ?? new SettingsManager(new ProjectSettings()); } public function supports(string $inputFormat): bool @@ -69,7 +76,7 @@ public function parse(ParserContext $parserContext, string $contents): DocumentN private function parseDocument(NodeWalker $walker, string $hash): DocumentNode { $document = new DocumentNode($hash, ltrim($this->getParserContext()->getCurrentAbsolutePath(), '/')); - $document->setOrphan(true); + $document->setOrphan(!$this->settingsManager->getProjectSettings()->isAutomaticMenu()); $this->document = $document; while ($event = $walker->next()) { diff --git a/packages/guides/src/Compiler/Passes/AutomaticMenuPass.php b/packages/guides/src/Compiler/Passes/AutomaticMenuPass.php new file mode 100644 index 000000000..8dee004fd --- /dev/null +++ b/packages/guides/src/Compiler/Passes/AutomaticMenuPass.php @@ -0,0 +1,63 @@ +settingsManager->getProjectSettings()->isAutomaticMenu()) { + return $documents; + } + + $projectNode = $compilerContext->getProjectNode(); + $rootDocumentEntry = $projectNode->getRootDocumentEntry(); + foreach ($documents as $documentNode) { + if ($documentNode->isOrphan()) { + // Do not add orphans to the automatic menu + continue; + } + + if ($documentNode->isRoot()) { + continue; + } + + $documentEntry = $projectNode->getDocumentEntry($documentNode->getFilePath()); + $documentEntry->setParent($rootDocumentEntry); + $rootDocumentEntry->addChild($documentEntry); + } + + return $documents; + } +} diff --git a/packages/guides/src/Compiler/Passes/GlobalMenuPass.php b/packages/guides/src/Compiler/Passes/GlobalMenuPass.php index b1891d7e2..2b980cfeb 100644 --- a/packages/guides/src/Compiler/Passes/GlobalMenuPass.php +++ b/packages/guides/src/Compiler/Passes/GlobalMenuPass.php @@ -30,6 +30,7 @@ use function array_map; use function assert; +use function sizeof; use const PHP_INT_MAX; @@ -78,11 +79,27 @@ public function run(array $documents, CompilerContextInterface $compilerContext) $menuNodes[] = $menuNode->withCaption($tocNode->getCaption()); } + if ($this->settingsManager->getProjectSettings()->isAutomaticMenu() && sizeof($menuNodes) === 0) { + $menuNodes[] = $this->getNavMenuNodeFromDocumentEntries($compilerContext); + } + $projectNode->setGlobalMenues($menuNodes); return $documents; } + private function getNavMenuNodeFromDocumentEntries(CompilerContextInterface $compilerContext): NavMenuNode + { + $menuEntries = []; + $rootDocumentEntry = $compilerContext->getProjectNode()->getRootDocumentEntry(); + foreach ($rootDocumentEntry->getChildren() as $documentEntryNode) { + $newMenuEntry = new InternalMenuEntryNode($documentEntryNode->getFile(), $documentEntryNode->getTitle(), [], false, 1); + $menuEntries[] = $newMenuEntry; + } + + return new NavMenuNode($menuEntries); + } + private function getNavMenuNodefromTocNode(CompilerContextInterface $compilerContext, TocNode $tocNode, string|null $menuType = null): NavMenuNode { $self = $this; diff --git a/packages/guides/src/Compiler/Passes/ToctreeValidationPass.php b/packages/guides/src/Compiler/Passes/ToctreeValidationPass.php index 208f40e1c..75a69bb9b 100644 --- a/packages/guides/src/Compiler/Passes/ToctreeValidationPass.php +++ b/packages/guides/src/Compiler/Passes/ToctreeValidationPass.php @@ -18,13 +18,20 @@ use phpDocumentor\Guides\Nodes\DocumentNode; use phpDocumentor\Guides\Nodes\DocumentTree\DocumentEntryNode; use phpDocumentor\Guides\Nodes\ProjectNode; +use phpDocumentor\Guides\Settings\ProjectSettings; +use phpDocumentor\Guides\Settings\SettingsManager; use Psr\Log\LoggerInterface; final class ToctreeValidationPass implements CompilerPass { + private SettingsManager $settingsManager; + public function __construct( private readonly LoggerInterface $logger, + SettingsManager|null $settingsManager = null, ) { + // if for backward compatibility reasons no settings manager was passed, use the defaults + $this->settingsManager = $settingsManager ?? new SettingsManager(new ProjectSettings()); } public function getPriority(): int @@ -39,6 +46,10 @@ public function getPriority(): int */ public function run(array $documents, CompilerContextInterface $compilerContext): array { + if ($this->settingsManager->getProjectSettings()->isAutomaticMenu()) { + return $documents; + } + $projectNode = $compilerContext->getProjectNode(); foreach ($documents as $document) { diff --git a/packages/guides/src/DependencyInjection/GuidesExtension.php b/packages/guides/src/DependencyInjection/GuidesExtension.php index 10d37c716..35a99614e 100644 --- a/packages/guides/src/DependencyInjection/GuidesExtension.php +++ b/packages/guides/src/DependencyInjection/GuidesExtension.php @@ -143,6 +143,7 @@ static function ($value) { ->scalarNode('show_progress')->end() ->scalarNode('links_are_relative')->end() ->scalarNode('max_menu_depth')->end() + ->scalarNode('automatic_menu')->end() ->arrayNode('base_template_paths') ->defaultValue([]) ->scalarPrototype()->end() @@ -278,6 +279,10 @@ public function load(array $configs, ContainerBuilder $container): void $projectSettings->setMaxMenuDepth((int) $config['max_menu_depth']); } + if (isset($config['automatic_menu'])) { + $projectSettings->setAutomaticMenu((bool) $config['automatic_menu']); + } + if (isset($config['default_code_language'])) { $projectSettings->setDefaultCodeLanguage((string) $config['default_code_language']); } diff --git a/packages/guides/src/Settings/ProjectSettings.php b/packages/guides/src/Settings/ProjectSettings.php index 1256ac701..08bdfd3eb 100644 --- a/packages/guides/src/Settings/ProjectSettings.php +++ b/packages/guides/src/Settings/ProjectSettings.php @@ -35,6 +35,7 @@ final class ProjectSettings private bool $linksRelative = false; private string $defaultCodeLanguage = ''; private int $maxMenuDepth = 0; + private bool $automaticMenu = false; /** @var string[] */ private array $ignoredDomains = []; @@ -243,4 +244,16 @@ public function setIndexName(string $indexName): ProjectSettings return $this; } + + public function isAutomaticMenu(): bool + { + return $this->automaticMenu; + } + + public function setAutomaticMenu(bool $automaticMenu): ProjectSettings + { + $this->automaticMenu = $automaticMenu; + + return $this; + } } diff --git a/tests/Integration/tests-full/markdown-full/default-menu-md/expected/anotherPage.html b/tests/Integration/tests-full/markdown-full/default-menu-md/expected/anotherPage.html index 40a7095c2..c7a3a2511 100644 --- a/tests/Integration/tests-full/markdown-full/default-menu-md/expected/anotherPage.html +++ b/tests/Integration/tests-full/markdown-full/default-menu-md/expected/anotherPage.html @@ -19,7 +19,22 @@ @@ -29,7 +44,23 @@
- + +
diff --git a/tests/Integration/tests-full/markdown-full/default-menu-md/expected/index.html b/tests/Integration/tests-full/markdown-full/default-menu-md/expected/index.html index eb4e8ef2e..3d78ead15 100644 --- a/tests/Integration/tests-full/markdown-full/default-menu-md/expected/index.html +++ b/tests/Integration/tests-full/markdown-full/default-menu-md/expected/index.html @@ -19,7 +19,22 @@
@@ -29,7 +44,23 @@
- + +
diff --git a/tests/Integration/tests-full/markdown-full/default-menu-md/expected/somePage.html b/tests/Integration/tests-full/markdown-full/default-menu-md/expected/somePage.html index 3fa4bdf7b..500644779 100644 --- a/tests/Integration/tests-full/markdown-full/default-menu-md/expected/somePage.html +++ b/tests/Integration/tests-full/markdown-full/default-menu-md/expected/somePage.html @@ -19,7 +19,22 @@
@@ -29,7 +44,23 @@
- + +
diff --git a/tests/Integration/tests-full/markdown-full/default-menu-md/input/guides.xml b/tests/Integration/tests-full/markdown-full/default-menu-md/input/guides.xml index 280ec62fe..4759d605e 100644 --- a/tests/Integration/tests-full/markdown-full/default-menu-md/input/guides.xml +++ b/tests/Integration/tests-full/markdown-full/default-menu-md/input/guides.xml @@ -5,6 +5,7 @@ theme="bootstrap" input-format="md" links-are-relative="1" + automatic-menu="true" > diff --git a/tests/Integration/tests-full/markdown-full/nested-menu-md/expected/dir2/index.html b/tests/Integration/tests-full/markdown-full/nested-menu-md/expected/dir2/index.html new file mode 100644 index 000000000..30dfc3d5e --- /dev/null +++ b/tests/Integration/tests-full/markdown-full/nested-menu-md/expected/dir2/index.html @@ -0,0 +1,121 @@ + + + + Dir 2 Title + + + + + + + +
+ + +
+
+
+
+
+
+ + +
+
+ + + +
+

Dir 2 Title

+ +

Lorem Ipsum Dolor.

+ +
+ +
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/tests/Integration/tests-full/markdown-full/nested-menu-md/expected/dir2/somePage.html b/tests/Integration/tests-full/markdown-full/nested-menu-md/expected/dir2/somePage.html new file mode 100644 index 000000000..25b2abeda --- /dev/null +++ b/tests/Integration/tests-full/markdown-full/nested-menu-md/expected/dir2/somePage.html @@ -0,0 +1,125 @@ + + + + Some Page in dir 2 + + + + + + + +
+ + +
+
+
+
+
+
+ + +
+
+ + + +
+

Some Page in dir 2

+ +

Lorem Ipsum Dolor.

+ +
+ +
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/tests/Integration/tests-full/markdown-full/nested-menu-md/expected/index.html b/tests/Integration/tests-full/markdown-full/nested-menu-md/expected/index.html new file mode 100644 index 000000000..69514672a --- /dev/null +++ b/tests/Integration/tests-full/markdown-full/nested-menu-md/expected/index.html @@ -0,0 +1,124 @@ + + + + Document Title + + + + + + + +
+ + +
+
+
+
+
+
+ + +
+
+ + + +
+

Document Title

+ +

Lorem Ipsum Dolor.

+ +
+ +
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/tests/Integration/tests-full/markdown-full/nested-menu-md/input/anotherPage.md b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/anotherPage.md new file mode 100644 index 000000000..02e0321a5 --- /dev/null +++ b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/anotherPage.md @@ -0,0 +1,3 @@ +# Another Page + +Lorem Ipsum Dolor. diff --git a/tests/Integration/tests-full/markdown-full/nested-menu-md/input/dir1/index.md b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/dir1/index.md new file mode 100644 index 000000000..862aaea1a --- /dev/null +++ b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/dir1/index.md @@ -0,0 +1,3 @@ +# Dir 1 Title + +Lorem Ipsum Dolor. diff --git a/tests/Integration/tests-full/markdown-full/nested-menu-md/input/dir2/index.md b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/dir2/index.md new file mode 100644 index 000000000..2f91b9fee --- /dev/null +++ b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/dir2/index.md @@ -0,0 +1,3 @@ +# Dir 2 Title + +Lorem Ipsum Dolor. diff --git a/tests/Integration/tests-full/markdown-full/nested-menu-md/input/dir2/somePage.md b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/dir2/somePage.md new file mode 100644 index 000000000..082675e84 --- /dev/null +++ b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/dir2/somePage.md @@ -0,0 +1,4 @@ + +# Some Page in dir 2 + +Lorem Ipsum `Dolor`. diff --git a/tests/Integration/tests-full/markdown-full/nested-menu-md/input/guides.xml b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/guides.xml new file mode 100644 index 000000000..4759d605e --- /dev/null +++ b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/guides.xml @@ -0,0 +1,11 @@ + + + + diff --git a/tests/Integration/tests-full/markdown-full/nested-menu-md/input/index.md b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/index.md new file mode 100644 index 000000000..9f6ae85ae --- /dev/null +++ b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/index.md @@ -0,0 +1,3 @@ +# Document Title + +Lorem Ipsum Dolor. diff --git a/tests/Integration/tests-full/markdown-full/nested-menu-md/input/skip b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/skip new file mode 100644 index 000000000..95484cd4d --- /dev/null +++ b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/skip @@ -0,0 +1 @@ +Nested autocreated menus are not yet supported \ No newline at end of file diff --git a/tests/Integration/tests-full/markdown-full/nested-menu-md/input/somePage.md b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/somePage.md new file mode 100644 index 000000000..bc2473dd3 --- /dev/null +++ b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/somePage.md @@ -0,0 +1,4 @@ + +# Some Page + +Lorem Ipsum `Dolor`. diff --git a/tests/Integration/tests-full/markdown-full/nested-menu-md/input/yetAnotherPage.md b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/yetAnotherPage.md new file mode 100644 index 000000000..fd7c625a3 --- /dev/null +++ b/tests/Integration/tests-full/markdown-full/nested-menu-md/input/yetAnotherPage.md @@ -0,0 +1,3 @@ +# Yet Another Page + +Lorem Ipsum Dolor.