--- /dev/null
+#!/usr/bin/env php
+<?php
+
+namespace mdref;
+
+use http\Env\Request;
+use http\Env\Response;
+use http\Message\Body;
+use function file_put_contents;
+
+require_once __DIR__."/../vendor/autoload.php";
+define("ROOT", dirname(__DIR__));
+define("REF2HTML", true);
+
+if ($argc < 3) {
+ fprintf(STDERR, "Usage: %s <basedir> <ref>[ <ref> ...]\n", $argv[0]);
+ fprintf(STDERR, " Note: the basedir will also be used as <base href>\n");
+ exit(1);
+}
+function say($fmt, ...$args) {
+ return fprintf(STDERR, $fmt, ...$args);
+};
+$out = $argv[1];
+if (!is_dir($out) && !mkdir($out, 0775, true)) {
+ fprintf(STDERR, "Could not create output directory %s\n", $out);
+ exit(1);
+}
+$nul = fopen("/dev/null", "w");
+$url = new BaseUrl("/" . $out . "/");
+$url->scheme = null;
+$url->host = null;
+$ref = new Reference(array_slice($argv, 2));
+$fmt = function(string $src, string $dst) use($ref, $out, $nul, $url) {
+ $req = new Request;
+ $req->setRequestMethod("GET");
+ $req->setRequestUrl($url . "./" . $src);
+ $res = new Response;
+ $res->setBody(new Body(fopen($dst, "w+")));
+ $act = new Action($ref, $req, $res, $url, $nul);
+ $act->handle();
+};
+$xfm = [
+ "php/PropertyProxy" => "propro/php/PropertyProxy",
+ "pq/Gateway" => "pq-gateway/pq/Gateway",
+ "pq/Query" => "pq-gateway/pq/Query",
+];
+$red = function($from, $dest, $name) use($out, $url) {
+ $from = $out . "/" . str_replace($dest, $from, $name);
+ if (!is_dir(dirname($from))) {
+ mkdir(dirname($from), 0775, true);
+ }
+ file_put_contents($from . ".html", <<<EOF
+<html>
+ <base href='$url'>
+ <meta http-equiv='refresh' content='0; $name'>
+</html>
+EOF
+);
+};
+$gen = function(Entry $entry) use($fmt, $out, $xfm, $red, &$gen) {
+ $src = $entry->getName();
+ $dir = $out . "/" . $src;
+ $dst = $dir . ".html";
+ foreach ($xfm as $from => $dest) {
+ if (strpos($src, $dest) !== false) {
+ say("Redirecting from %s to %s\n", $from, $dest);
+ $red($from, $dest, $src);
+ break;
+ }
+ }
+ if ($entry->hasIterator()) {
+ if (!is_dir($dir)) {
+ mkdir($dir, 0755, true);
+ }
+ foreach ($entry as $subentry) {
+ $gen($subentry);
+ }
+ }
+ say("Generating %s from %s\n", $dst, $src);
+ $fmt($src, $dst);
+};
+/** @var $repo Repo */
+foreach ($ref as $repo) {
+ say("Entering ref %s\n", $repo->getName());
+ if (is_file($stub = $repo->getPath($repo->getName().".stub.php"))) {
+ copy($stub, $out . "/" . basename($stub));
+ }
+ foreach ($repo as $root) {
+ $gen($root);
+ }
+}
+$fmt("", $out . "/" . "index.html");
+
+$presets = [
+ "AUTHORS",
+ "LICENSE",
+ "VERSION",
+ "public/index.css" => "index.css",
+ "public/index.js" => "index.js",
+ "public/favicon.ico" => "favicon.ico",
+];
+foreach ($presets as $src => $dst) {
+ if (!is_string($src)) {
+ $src = $dst;
+ }
+ copy(ROOT . "/" . $src, $out . "/" . $dst);
+}
+// no jekyll
+touch($out . "/.nojekyll");
+// htacess for apache
+file_put_contents($out . "/.htaccess", <<<EOF
+Options -Indexes +MultiViews +FollowSymLinks
+DirectorySlash Off
+
+RewriteEngine On
+RewriteCond %{REQUEST_FILENAME} -d
+RewriteRule ^(.+)$ $1.html [L]
+
+<Files *.php>
+ ForceType text/x-php
+ SetHandler default-handler
+</Files>
+
+EOF
+);
"email": "mike@php.net"
}
],
- "bin": ["bin/ref2stub"],
+ "bin": [
+ "bin/ref2stub",
+ "bin/ref2html"
+ ],
"autoload": {
"psr-4": {
"mdref\\": "mdref/"
}
},
"require": {
- "php": "^7.3",
- "ext-ctype": "^7.3",
- "ext-http": "^3.2",
- "ext-filter": "^7.3",
- "ext-pcre": "^7.3"
+ "php": "^7.3 || ^8.0",
+ "ext-ctype": "*",
+ "ext-filter": "*",
+ "ext-pcre": "*",
+ "ext-http": "^3.2 || ^4.2",
+ "league/commonmark": "^2.0"
},
"suggests": {
- "ext-discount": "A Markdown renderer is needed, this is the preferred one.",
- "ext-cmark": "A Markdown renderer is needed, this is the fallback one."
+ "ext-discount": "A Markdown renderer is needed, this is the preferred one."
}
}
--- /dev/null
+<?php
+
+namespace mdref;
+
+use function class_exists;
+
+abstract class Formatter {
+ abstract function formatString(string $string) : string;
+ abstract function formatFile(string $file) : string;
+
+ static function factory() : Formatter {
+ if (class_exists("League\\CommonMark\\GithubFlavoredMarkdownConverter", true)) {
+ return new Formatter\League;
+ }
+ if (extension_loaded("discount")) {
+ return new Formatter\Discount;
+ }
+ throw new \Exception("No Markdown implementation found");
+ }
+}
--- /dev/null
+<?php
+
+namespace mdref\Formatter;
+
+use mdref\Exception;
+use mdref\Formatter;
+
+use MarkdownDocument;
+
+class Discount extends Formatter {
+
+ function formatString(string $string) : string {
+ $md = \MarkdownDocument::createFromString($string);
+ $md->compile(\MarkdownDocument::AUTOLINK);
+ return $md->getHtml();
+ }
+
+ function formatFile(string $file) : string {
+ $fd = fopen($file, "r");
+ if (!$fd) {
+ throw Exception::fromLastError();
+ }
+
+ $md = \MarkdownDocument::createFromStream($fd);
+ $md->compile(\MarkdownDocument::AUTOLINK | \MarkdownDocument::TOC);
+ $html = $md->getHtml();
+
+ fclose($fd);
+
+ return $html;
+ }
+}
--- /dev/null
+<?php
+
+namespace mdref\Formatter;
+
+use mdref\Exception;
+use mdref\Formatter;
+
+use League\CommonMark\Extension;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+use League\CommonMark\Normalizer;
+
+use function file_get_contents;
+use function preg_replace;
+
+class League extends Formatter {
+ private $md;
+
+ function __construct() {
+ $this->md = new GithubFlavoredMarkdownConverter([
+ "slug_normalizer" => [
+ "instance" => new class implements Normalizer\TextNormalizerInterface {
+ function normalize(string $text, $context = null) : string {
+ return preg_replace("/[^[:alnum:]:._-]/", ".", $text);
+ }
+ }
+ ],
+ "heading_permalink" => [
+ "html_class" => "permalink",
+ "id_prefix" => "",
+ "fragment_prefix" => "",
+ "title" => "",
+ "symbol" => "#",
+ "insert" => "after",
+ "min_heading_level" => 2,
+ ]
+ ]);
+ $this->md->getEnvironment()->addExtension(
+ new Extension\DescriptionList\DescriptionListExtension
+ );
+ $this->md->getEnvironment()->addExtension(
+ new Extension\HeadingPermalink\HeadingPermalinkExtension
+ );
+ $this->md->getEnvironment()->addExtension(
+ new Extension\Attributes\AttributesExtension
+ );
+ }
+
+ function formatString(string $string) : string {
+ return $this->md->convertToHtml($string);
+ }
+
+ function formatFile(string $file) : string {
+ $string = file_get_contents($file);
+ if ($string === false) {
+ throw Exception::fromLastError();
+ }
+ return $this->md->convertToHtml($string);
+ }
+}
*/
private $repos = array();
+ /**
+ * @var Formatter
+ */
+ private $fmt;
+
/**
* @param array $refs list of mdref repository paths
*/
- public function __construct(array $refs) {
+ public function __construct(array $refs, Formatter $fmt = null) {
foreach ($refs as $path) {
$repo = new Repo($path);
$this->repos[$repo->getName()] = $repo;
}
+ $this->fmt = $fmt ?: Formatter::factory();
}
/**
/**
* @param string $string
* @return string
- * @throws \Exception
+ * @throws \Exception, Exception
*/
public function formatString(string $string) : string {
- if (extension_loaded("discount")) {
- $md = \MarkdownDocument::createFromString($string);
- $md->compile(\MarkdownDocument::AUTOLINK);
- return $md->getHtml();
- }
- if (extension_loaded("cmark")) {
- $node = \CommonMark\Parse($string);
- return \CommonMark\Render\HTML($node);
- }
- throw new \Exception("No Markdown implementation found");
+ return $this->fmt->formatString($string);
}
/**
* @param string $file
* @return string
- * @throws \Exception
+ * @throws \Exception, Exception
*/
public function formatFile(string $file) : string {
- if (extension_loaded("discount")) {
- $fd = fopen($file, "r");
- $md = \MarkdownDocument::createFromStream($fd);
- $md->compile(\MarkdownDocument::AUTOLINK | \MarkdownDocument::TOC);
- $html = $md->getHtml();
- fclose($fd);
- return $html;
- }
- if (extension_loaded("cmark")) {
- $node = \CommonMark\Parse(file_get_contents($file));
- return \CommonMark\Render\HTML($node);
- }
- throw new \Exception("No Markdown implementation found");
+ return $this->fmt->formatFile($file);
}
}
use http\Env\Response;
use function ini_get;
use function ini_set;
-use function spl_autoload_register;
-use function strncmp;
-use function strtr;
use const GLOB_ONLYDIR;
use const PATH_SEPARATOR;
use const REFS;
date_default_timezone_set("UTC");
}
-spl_autoload_register(function($c) {
- if (!strncmp($c, "mdref\\", 6)) {
- return require ROOT . "/" . strtr($c, "\\", "/") . ".php";
- }
-});
+require_once __DIR__ . "/../vendor/autoload.php";
$response = new Response;
$ehandler = new ExceptionHandler($response);
<p><strong>Download the Stub file:</strong></p>
<ul style="list-style-type: '»'">
<li>
+ <?php if (defined("REF2HTML") && constant("REF2HTML")) :?>
+ <a href="<?= $entry->getName() ?>.stub.php"><?= $entry->getName() ?>.stub.php</a><br>
+ <?php else : ?>
<a href="stub?ref=<?= $entry->getName() ?>"><?= $entry->getName() ?>.stub.php</a><br>
+ <?php endif; ?>
<small>
Last modified:
<?= date_create("@".filemtime($stub))->setTimezone(new DateTimezone("UTC"))->format("Y-m-d H:i:s T") ?>
</li>
</ul>
</div>
-