diff --git a/Facades/DocsFacade/MarkdownPrinters/ActionMarkdownPrinter.php b/Facades/DocsFacade/MarkdownPrinters/ActionMarkdownPrinter.php new file mode 100644 index 000000000..d8d6814f2 --- /dev/null +++ b/Facades/DocsFacade/MarkdownPrinters/ActionMarkdownPrinter.php @@ -0,0 +1,82 @@ +workbench = $workbench; + $this->action = $action; + $this->headingLevel = $headingLevel; + } + + /** + * Builds and returns the complete Markdown for the current action + */ + public function getMarkdown(): string + { + $heading = MarkdownDataType::buildMarkdownHeader($this->action->getName(), $this->headingLevel); + + $uxon = $this->action->exportUxonObject(); + + $uxon = $uxon->toJson(); + //Uxon + + //TODO Einbauen Uxon im Codeblock, mögliche Description + + return <<workbench = $workbench; + + if ($filePath) { + + $normalizedPath = $this->normalizePath(rawurldecode($filePath)); + + [$appAlias, $relativePath] = $this->extractAppAndRelativePath($normalizedPath); + + if ($appAlias !== '') { + $this->app = $this->workbench->getApp($appAlias); + } + + if ($relativePath !== '') { + $this->docsPath = $relativePath; + } + } + } + + /** + * Reads the markdown document and returns its content. + * * + * @return string Markdown content + */ + public function getMarkdown(): string + { + $path = $this->getAbsolutePath(); + if(!$path){ + return 'ERROR: file not found!'; + } + if(!StringDataType::endsWith($path, '.php')) { + return "ERROR: This path does not refer to a PHP file. Therefore, the file could not be read."; + } + + return $this->rebasePaths($this->readFile($path)); + } + + /** + * Normalizes a file path to use a consistent directory separator. + * + * All slash variants are converted to the system directory separator + * and duplicate separators are collapsed. + * + * @param string $path Raw path + * @return string Normalized path + */ + protected function normalizePath(string $path): string + { + $path = str_replace(['\/', '\\'], '/', $path); + $path = preg_replace('#/+#', '/', $path); + $path = str_replace('/', DIRECTORY_SEPARATOR, $path); + + $pattern = '#'.preg_quote(DIRECTORY_SEPARATOR).'+' . '#'; + $path = preg_replace($pattern, DIRECTORY_SEPARATOR, $path); + + return $path; + } + + /** + * Extracts app alias and relative path from an api docs path. + * + * Expected pattern: + * api/docs/Vendor/App/some/path/file.php + * becomes: + * alias: "vendor.app" + * relativePath: "some/path/file.php" + * + * @param string $link Normalized path + * @return array{0:string,1:string} [appAlias, relativePath] + */ + protected function extractAppAndRelativePath(string $link): array + { + $link = $this->normalizePath($link); + + $ds = preg_quote(DIRECTORY_SEPARATOR, '#'); + $pattern = "#api{$ds}docs{$ds}([^{$ds}]+){$ds}([^{$ds}]+){$ds}(.+)$#i"; + + if (preg_match($pattern, $link, $m)) { + $appAlias = strtolower($m[1] . "." . $m[2]); + $relativePath = $m[3]; + return [$appAlias, $relativePath]; + } + + return ['', '']; + } + + /** + * Returns the absolute file system path to the current markdown file. + * + * @return string Absolute path to the markdown file + */ + public function getAbsolutePath(): ?string + { + if (! $this->app || ! $this->docsPath) { + return null; + } + + return $this->app->getDirectoryAbsolutePath() + . DIRECTORY_SEPARATOR + . $this->docsPath; + } + + + + /** + * Reads the content of a markdown file from disk. + * + * If the file does not exist an error message is returned instead. + * + * @param string $filePath Absolute path to the markdown file + * @return string File content or error message + */ + protected function readFile(string $filePath): string + { + if (! file_exists($filePath)) { + return 'ERROR: file not found!'; + } + + $md = file_get_contents($filePath); + return $md === false ? '' : $md; + } + + /** + * Rewrites specific PHP use statements by inserting the api docs prefix. + * + * The raw input contains PHP code as a string. All matching use statements + * beginning with "use exface\" are rewritten so they begin with + * "use api\docs\exface\" instead. Other lines remain unchanged. + */ + protected function rebasePaths(string $raw) : string + { + return preg_replace( + '/^use\s+exface\\\\(.*);/m', + 'use api\\docs\\exface\\\\$1;', + $raw + ); + } + + + + + +} \ No newline at end of file diff --git a/Facades/DocsFacade/MarkdownPrinters/ObjectMarkdownPrinter.php b/Facades/DocsFacade/MarkdownPrinters/ObjectMarkdownPrinter.php index 303135e7c..a913fd3ff 100644 --- a/Facades/DocsFacade/MarkdownPrinters/ObjectMarkdownPrinter.php +++ b/Facades/DocsFacade/MarkdownPrinters/ObjectMarkdownPrinter.php @@ -11,12 +11,14 @@ use exface\Core\Facades\DocsFacade; use exface\Core\Factories\MetaObjectFactory; use exface\Core\Factories\QueryBuilderFactory; +use exface\Core\Interfaces\Actions\ActionInterface; use exface\Core\Interfaces\Model\BehaviorInterface; use exface\Core\Interfaces\Model\MetaAttributeInterface; use exface\Core\Interfaces\Model\MetaAttributeListInterface; use exface\Core\Interfaces\Model\MetaObjectInterface; use exface\Core\Interfaces\Model\MetaRelationInterface; use exface\Core\Interfaces\WorkbenchInterface; +use Respect\Validation\Rules\Length; /** * Builds a Markdown documentation view for a meta object and its related objects. @@ -87,7 +89,10 @@ public function getMarkdown(): string $importantAttributes = trim($importantAttributes); $attributesHeading = MarkdownDataType::buildMarkdownHeader("Attributes of \"{$metaObject->getName()}\"", $headingLevel + 1); - + + $actionHeading = MarkdownDataType::buildMarkdownHeader("Actions of \"{$metaObject->getName()}\"", $headingLevel + 1); + + $markdown = <<buildMdAttributesSections($metaObject, $headingLevel+2)} +{$this->buildMdActionSection($actionHeading, $metaObject, $headingLevel+2 )} + {$this->buildMdBehaviorsSections($metaObject, 'Behaviors of "' . $metaObject->getName() . '"', $headingLevel+1)} {$this->buildMdRelatedObjects($metaObject->getRelations(), 'Related objects', $headingLevel)} @@ -172,6 +179,22 @@ protected function buildMarkDownAttributeSection(MetaAttributeInterface $attr, i {$this->buildMdUxonCodeblock($attr->getCustomDataTypeUxon(), 'Configuration of data type [' . $dataType->getAliasWithNamespace() . '](' . $dataTypeLink . '):')} +MD; + + } + + protected function buildMdActionSection(string $header, MetaObjectInterface $obj, int $headingLevel = 3) : string + { + + $markdown = ''; + foreach ($obj->getActions() as $act) { + $actionPrinter = new ActionMarkdownPrinter($this->workbench, $act, $headingLevel); + $markdown .= $actionPrinter->getMarkdown(); + } + return <<getUri()->getPath(), diff --git a/Interfaces/Facades/MarkdownPrinterMiddlewareInterface.php b/Interfaces/Facades/MarkdownPrinterMiddlewareInterface.php index 029e47d9b..651dab9c9 100644 --- a/Interfaces/Facades/MarkdownPrinterMiddlewareInterface.php +++ b/Interfaces/Facades/MarkdownPrinterMiddlewareInterface.php @@ -8,4 +8,7 @@ interface MarkdownPrinterMiddlewareInterface extends MiddlewareInterface { public function getMarkdown(ServerRequestInterface $request) : string; + + + public function shouldSkip(ServerRequestInterface $request) : bool; } \ No newline at end of file