@kirigami/php-prepros 3.2.1 → 3.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -13
- package/package.json +1 -1
- package/src/libraries/ld.class.php +3 -2
- package/src/libraries/md.class.php +57 -57
- package/src/libraries/md.plugins.php +79 -102
- package/src/libraries/meta.class.php +3 -2
package/README.md
CHANGED
|
@@ -249,7 +249,7 @@ seo: seo:
|
|
|
249
249
|
|
|
250
250
|
Positional args: source path (relative to `image.source`), width, height,
|
|
251
251
|
and the literal `cover` keyword. Registered in `md.plugins.php` alongside
|
|
252
|
-
`codepen`/`youtube`/`
|
|
252
|
+
`codepen`/`youtube`/`callout` — available out of the box, drop
|
|
253
253
|
it with `MD::unregisterPlugin('img-asset')` if you don't want it.
|
|
254
254
|
|
|
255
255
|
---
|
|
@@ -2009,18 +2009,6 @@ Embeds a CodePen result via `<iframe>`. `user` defaults to `anonymous`, `height`
|
|
|
2009
2009
|
{% codepen abcXYZ jsmith 500 %}
|
|
2010
2010
|
```
|
|
2011
2011
|
|
|
2012
|
-
#### `{% checklist ["Title"] items %}`
|
|
2013
|
-
|
|
2014
|
-
Renders a block-syntax list of checkbox items, one per line, with an optional title.
|
|
2015
|
-
|
|
2016
|
-
```
|
|
2017
|
-
{% checklist "Today"
|
|
2018
|
-
Do the dishes
|
|
2019
|
-
Walk the dog
|
|
2020
|
-
Read a book
|
|
2021
|
-
%}
|
|
2022
|
-
```
|
|
2023
|
-
|
|
2024
2012
|
---
|
|
2025
2013
|
|
|
2026
2014
|
## Extending the `<markdown>` tag
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kirigami/php-prepros",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.2",
|
|
4
4
|
"description": "PHP preprocessor for the Kirigami static site generator. Compile PHP page templates to clean, deployable HTML — with zero server dependency.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kirigami",
|
|
@@ -746,8 +746,9 @@ final class LD
|
|
|
746
746
|
if ($url === null || $url === '') return null;
|
|
747
747
|
if (preg_match('#^(https?:)?//#', $url) || str_starts_with($url, 'data:')) return $url;
|
|
748
748
|
|
|
749
|
-
|
|
750
|
-
|
|
749
|
+
// Against the whole baseurl, path included: a site on `user.github.io/repo` keeps `/repo`.
|
|
750
|
+
$base = rtrim((string) (self::data()->baseurl ?? ''), '/');
|
|
751
|
+
return $base . '/' . ltrim($url, '/');
|
|
751
752
|
}
|
|
752
753
|
|
|
753
754
|
/** @return array<int,string> */
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
<?php
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* MD — Markdown renderer backed by the native `mdhtml` extension (CommonMark
|
|
5
|
-
* + GFM via cmark-gfm 0.29.0.gfm.13, statically built into @kirigami/php-wasm
|
|
6
|
-
* — see php-kirigami/php-mdhtml).
|
|
7
|
-
*
|
|
8
|
-
* Switched from the hand-written recursive-descent/regex renderer to this
|
|
9
|
-
* native extension — see docs/DECISIONS.md and docs/STATUS.md in the repo
|
|
10
|
-
* root for the full reasoning. Every MD::toHtml() extension (plugins, emoji,
|
|
11
|
-
* GFM alerts, definition lists, heading anchors, ==highlight==/^sup^/~sub~)
|
|
12
|
-
* is reimplemented in C, not just the CommonMark/GFM core — see php-mdhtml's
|
|
13
|
-
* README for exactly what's covered.
|
|
14
|
-
*
|
|
15
|
-
* Kept the old implementation as MD_LEGACY (md-legacy.class.php) — untouched,
|
|
16
|
-
* still autoloadable — as a rollback path.
|
|
17
|
-
*
|
|
18
|
-
* Usage:
|
|
19
|
-
* $html = MD::toHtml($markdown);
|
|
20
|
-
* MD::registerPlugin('name', function (array $args, string $body): string { ... });
|
|
21
|
-
* MD::registerEmoji('kirigami', '📐');
|
|
22
|
-
*/
|
|
23
|
-
class MD
|
|
24
|
-
{
|
|
25
|
-
public static function registerPlugin(string $name, callable $callback): void
|
|
26
|
-
{
|
|
27
|
-
\MDHtml\RegisterPlugin($name, $callback);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public static function unregisterPlugin(string $name): void
|
|
31
|
-
{
|
|
32
|
-
\MDHtml\UnregisterPlugin($name);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
public static function getRegisteredPlugins(): array
|
|
36
|
-
{
|
|
37
|
-
return \MDHtml\GetRegisteredPlugins();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
public static function registerEmoji(string $shortcode, string $char): void
|
|
41
|
-
{
|
|
42
|
-
\MDHtml\RegisterEmoji($shortcode, $char);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
public static function toHtml(string $markdown): string
|
|
46
|
-
{
|
|
47
|
-
return \MDHtml\Render($markdown);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
// Default Markdown plugins ({% codepen %}, {%
|
|
53
|
-
// {% img-asset %}) — "registered out of the box" per the README. Loaded here
|
|
54
|
-
// so every entrypoint (prepros.php, runenv.php, imagebatch.php) gets them
|
|
55
|
-
// without an explicit include. A project can still MD::unregisterPlugin() any
|
|
56
|
-
// of them, or MD::registerPlugin() its own with the same name to override.
|
|
57
|
-
include_once(__DIR__ . '/md.plugins.php');
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MD — Markdown renderer backed by the native `mdhtml` extension (CommonMark
|
|
5
|
+
* + GFM via cmark-gfm 0.29.0.gfm.13, statically built into @kirigami/php-wasm
|
|
6
|
+
* — see php-kirigami/php-mdhtml).
|
|
7
|
+
*
|
|
8
|
+
* Switched from the hand-written recursive-descent/regex renderer to this
|
|
9
|
+
* native extension — see docs/DECISIONS.md and docs/STATUS.md in the repo
|
|
10
|
+
* root for the full reasoning. Every MD::toHtml() extension (plugins, emoji,
|
|
11
|
+
* GFM alerts, definition lists, heading anchors, ==highlight==/^sup^/~sub~)
|
|
12
|
+
* is reimplemented in C, not just the CommonMark/GFM core — see php-mdhtml's
|
|
13
|
+
* README for exactly what's covered.
|
|
14
|
+
*
|
|
15
|
+
* Kept the old implementation as MD_LEGACY (md-legacy.class.php) — untouched,
|
|
16
|
+
* still autoloadable — as a rollback path.
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
* $html = MD::toHtml($markdown);
|
|
20
|
+
* MD::registerPlugin('name', function (array $args, string $body): string { ... });
|
|
21
|
+
* MD::registerEmoji('kirigami', '📐');
|
|
22
|
+
*/
|
|
23
|
+
class MD
|
|
24
|
+
{
|
|
25
|
+
public static function registerPlugin(string $name, callable $callback): void
|
|
26
|
+
{
|
|
27
|
+
\MDHtml\RegisterPlugin($name, $callback);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public static function unregisterPlugin(string $name): void
|
|
31
|
+
{
|
|
32
|
+
\MDHtml\UnregisterPlugin($name);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public static function getRegisteredPlugins(): array
|
|
36
|
+
{
|
|
37
|
+
return \MDHtml\GetRegisteredPlugins();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public static function registerEmoji(string $shortcode, string $char): void
|
|
41
|
+
{
|
|
42
|
+
\MDHtml\RegisterEmoji($shortcode, $char);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public static function toHtml(string $markdown): string
|
|
46
|
+
{
|
|
47
|
+
return \MDHtml\Render($markdown);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
// Default Markdown plugins ({% codepen %}, {% callout %},
|
|
53
|
+
// {% img-asset %}) — "registered out of the box" per the README. Loaded here
|
|
54
|
+
// so every entrypoint (prepros.php, runenv.php, imagebatch.php) gets them
|
|
55
|
+
// without an explicit include. A project can still MD::unregisterPlugin() any
|
|
56
|
+
// of them, or MD::registerPlugin() its own with the same name to override.
|
|
57
|
+
include_once(__DIR__ . '/md.plugins.php');
|
|
@@ -1,103 +1,80 @@
|
|
|
1
|
-
<?php
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// =============================================================================
|
|
6
|
-
// DEFAULT MARKDOWN PLUGINS
|
|
7
|
-
//
|
|
8
|
-
// Auto-loaded from md.class.php, so these are available in every render without
|
|
9
|
-
// any setup ("registered out of the box"). To drop one, call
|
|
10
|
-
// MD::unregisterPlugin('name') (or md_unregister_plugin('name')) from an
|
|
11
|
-
// `includes` file; to change one, MD::registerPlugin() your own under the same
|
|
12
|
-
// name.
|
|
13
|
-
// =============================================================================
|
|
14
|
-
|
|
15
|
-
// --- CodePen (inline) ---
|
|
16
|
-
// {% codepen PENid %}
|
|
17
|
-
// {% codepen PENid user height %}
|
|
18
|
-
MD::registerPlugin('codepen', function (array $args, string $body): string {
|
|
19
|
-
$id = htmlspecialchars($args[0] ?? '', ENT_QUOTES, 'UTF-8');
|
|
20
|
-
$user = htmlspecialchars($args[1] ?? 'anonymous', ENT_QUOTES, 'UTF-8');
|
|
21
|
-
$height = intval($args[2] ?? 400);
|
|
22
|
-
if ($id === '') return '<!-- codepen: missing id -->';
|
|
23
|
-
return "<iframe height=\"{$height}\" style=\"width:100%\" "
|
|
24
|
-
. "scrolling=\"no\" "
|
|
25
|
-
. "src=\"https://codepen.io/{$user}/embed/{$id}?default-tab=result\" "
|
|
26
|
-
. "frameborder=\"no\" loading=\"lazy\" allowfullscreen>"
|
|
27
|
-
. "</iframe>";
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// ---
|
|
31
|
-
// {%
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
$
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// {% img-asset photo.jpg %}
|
|
81
|
-
// {% img-asset photo.jpg 800 %}
|
|
82
|
-
// {% img-asset photo.jpg 800 600 %}
|
|
83
|
-
// {% img-asset photo.jpg 800 600 cover %}
|
|
84
|
-
MD::registerPlugin('img-asset', function (array $args, string $body): string {
|
|
85
|
-
$path = trim($args[0] ?? '');
|
|
86
|
-
if ($path === '') return '<!-- img-asset: missing path -->';
|
|
87
|
-
|
|
88
|
-
$width = isset($args[1]) ? (int) $args[1] : 0;
|
|
89
|
-
$height = isset($args[2]) ? (int) $args[2] : 0;
|
|
90
|
-
$cover = isset($args[3]) && strtolower($args[3]) === 'cover';
|
|
91
|
-
|
|
92
|
-
// A resolvable path is required to actually call IMG::asset() — this
|
|
93
|
-
// also protects a literal `{% img-asset path … %}` written as Markdown
|
|
94
|
-
// *documentation* (inside a code span): the plugin still runs even when
|
|
95
|
-
// its output ends up discarded for the literal text, so a placeholder
|
|
96
|
-
// path must not throw.
|
|
97
|
-
try {
|
|
98
|
-
$src = IMG::asset($path, $width, $height, $cover, PREPROS::$file);
|
|
99
|
-
} catch (Throwable $e) {
|
|
100
|
-
return '<!-- img-asset: ' . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8') . ' -->';
|
|
101
|
-
}
|
|
102
|
-
return '<img src="' . htmlspecialchars($src, ENT_QUOTES, 'UTF-8') . '" alt="">';
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
// =============================================================================
|
|
6
|
+
// DEFAULT MARKDOWN PLUGINS
|
|
7
|
+
//
|
|
8
|
+
// Auto-loaded from md.class.php, so these are available in every render without
|
|
9
|
+
// any setup ("registered out of the box"). To drop one, call
|
|
10
|
+
// MD::unregisterPlugin('name') (or md_unregister_plugin('name')) from an
|
|
11
|
+
// `includes` file; to change one, MD::registerPlugin() your own under the same
|
|
12
|
+
// name.
|
|
13
|
+
// =============================================================================
|
|
14
|
+
|
|
15
|
+
// --- CodePen (inline) ---
|
|
16
|
+
// {% codepen PENid %}
|
|
17
|
+
// {% codepen PENid user height %}
|
|
18
|
+
MD::registerPlugin('codepen', function (array $args, string $body): string {
|
|
19
|
+
$id = htmlspecialchars($args[0] ?? '', ENT_QUOTES, 'UTF-8');
|
|
20
|
+
$user = htmlspecialchars($args[1] ?? 'anonymous', ENT_QUOTES, 'UTF-8');
|
|
21
|
+
$height = intval($args[2] ?? 400);
|
|
22
|
+
if ($id === '') return '<!-- codepen: missing id -->';
|
|
23
|
+
return "<iframe height=\"{$height}\" style=\"width:100%\" "
|
|
24
|
+
. "scrolling=\"no\" "
|
|
25
|
+
. "src=\"https://codepen.io/{$user}/embed/{$id}?default-tab=result\" "
|
|
26
|
+
. "frameborder=\"no\" loading=\"lazy\" allowfullscreen>"
|
|
27
|
+
. "</iframe>";
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// --- Custom callout (inline or block) ---
|
|
31
|
+
// Inline: {% callout warning "Warning!" Content on one line %}
|
|
32
|
+
// Block : {% callout danger "Title"
|
|
33
|
+
// Paragraph 1
|
|
34
|
+
//
|
|
35
|
+
// Paragraph 2
|
|
36
|
+
// %}
|
|
37
|
+
MD::registerPlugin('callout', function (array $args, string $body): string {
|
|
38
|
+
$validTypes = ['info', 'success', 'warning', 'danger'];
|
|
39
|
+
$type = in_array($args[0] ?? '', $validTypes, true) ? $args[0] : 'info';
|
|
40
|
+
$title = !empty($args[1]) ? htmlspecialchars($args[1], ENT_QUOTES, 'UTF-8') : '';
|
|
41
|
+
|
|
42
|
+
// Content: $body for a block tag, otherwise the remaining args on the opening line
|
|
43
|
+
if ($body !== '') {
|
|
44
|
+
$content = htmlspecialchars($body, ENT_QUOTES, 'UTF-8');
|
|
45
|
+
// Replace double line breaks with <br><br> to preserve paragraphs
|
|
46
|
+
$content = str_replace("\n\n", '<br><br>', $content);
|
|
47
|
+
$content = str_replace("\n", '<br>', $content);
|
|
48
|
+
} else {
|
|
49
|
+
$content = htmlspecialchars(implode(' ', array_slice($args, $title ? 2 : 1)), ENT_QUOTES, 'UTF-8');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
$titleHtml = $title ? "<strong>{$title}</strong><br>" : '';
|
|
53
|
+
return "<div class=\"callout callout-{$type}\">{$titleHtml}{$content}</div>";
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// --- Image asset (inline) — same pipeline as <img asset>, via IMG::asset() ---
|
|
57
|
+
// {% img-asset photo.jpg %}
|
|
58
|
+
// {% img-asset photo.jpg 800 %}
|
|
59
|
+
// {% img-asset photo.jpg 800 600 %}
|
|
60
|
+
// {% img-asset photo.jpg 800 600 cover %}
|
|
61
|
+
MD::registerPlugin('img-asset', function (array $args, string $body): string {
|
|
62
|
+
$path = trim($args[0] ?? '');
|
|
63
|
+
if ($path === '') return '<!-- img-asset: missing path -->';
|
|
64
|
+
|
|
65
|
+
$width = isset($args[1]) ? (int) $args[1] : 0;
|
|
66
|
+
$height = isset($args[2]) ? (int) $args[2] : 0;
|
|
67
|
+
$cover = isset($args[3]) && strtolower($args[3]) === 'cover';
|
|
68
|
+
|
|
69
|
+
// A resolvable path is required to actually call IMG::asset() — this
|
|
70
|
+
// also protects a literal `{% img-asset path … %}` written as Markdown
|
|
71
|
+
// *documentation* (inside a code span): the plugin still runs even when
|
|
72
|
+
// its output ends up discarded for the literal text, so a placeholder
|
|
73
|
+
// path must not throw.
|
|
74
|
+
try {
|
|
75
|
+
$src = IMG::asset($path, $width, $height, $cover, PREPROS::$file);
|
|
76
|
+
} catch (Throwable $e) {
|
|
77
|
+
return '<!-- img-asset: ' . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8') . ' -->';
|
|
78
|
+
}
|
|
79
|
+
return '<img src="' . htmlspecialchars($src, ENT_QUOTES, 'UTF-8') . '" alt="">';
|
|
103
80
|
});
|
|
@@ -458,8 +458,9 @@ final class META
|
|
|
458
458
|
$url = trim($url);
|
|
459
459
|
if (preg_match('#^(https?:)?//#', $url) || str_starts_with($url, 'data:')) return $url;
|
|
460
460
|
|
|
461
|
-
|
|
462
|
-
|
|
461
|
+
// Against the whole baseurl, path included: a site on `user.github.io/repo` keeps `/repo`.
|
|
462
|
+
$base = rtrim((string) (self::data()->baseurl ?? ''), '/');
|
|
463
|
+
return $base === '' ? $url : $base . '/' . ltrim($url, '/');
|
|
463
464
|
}
|
|
464
465
|
|
|
465
466
|
/** `@user` / `user` / `https://twitter.com/user` → `@user`. */
|