@kirigami/php-prepros 3.2.0 → 3.2.1

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/package.json CHANGED
@@ -1,59 +1,59 @@
1
- {
2
- "name": "@kirigami/php-prepros",
3
- "version": "3.2.0",
4
- "description": "PHP preprocessor for the Kirigami static site generator. Compile PHP page templates to clean, deployable HTML — with zero server dependency.",
5
- "keywords": [
6
- "kirigami",
7
- "php",
8
- "preprocessor",
9
- "static-site-generator",
10
- "ssg",
11
- "wasm",
12
- "php-wasm",
13
- "markdown",
14
- "yaml",
15
- "github-pages",
16
- "pages"
17
- ],
18
- "license": "GPL-3.0-or-later",
19
- "author": "Maxime Larrivée-Roy",
20
- "type": "module",
21
- "main": "index.js",
22
- "types": "index.d.ts",
23
- "files": [
24
- "index.js",
25
- "index.d.ts",
26
- "src/",
27
- "LICENSE",
28
- "README.md"
29
- ],
30
- "engines": {
31
- "node": ">=24.0.0",
32
- "npm": ">=10.2.3"
33
- },
34
- "exports": {
35
- ".": {
36
- "import": "./index.js"
37
- },
38
- "./package.json": "./package.json"
39
- },
40
- "publishConfig": {
41
- "access": "public"
42
- },
43
- "scripts": {
44
- "test": "node --test --test-concurrency=1 \"test/*.test.js\""
45
- },
46
- "dependencies": {
47
- "@kirigami/php-wasm": "8.5.11-1",
48
- "@kirigami/struct-walker": "1.0.6",
49
- "picomatch": "^4.0.7"
50
- },
51
- "repository": {
52
- "type": "git",
53
- "url": "git+https://github.com/php-kirigami/kirigami.git"
54
- },
55
- "homepage": "https://php-kirigami.github.io",
56
- "bugs": {
57
- "url": "https://github.com/php-kirigami/kirigami/issues"
58
- }
59
- }
1
+ {
2
+ "name": "@kirigami/php-prepros",
3
+ "version": "3.2.1",
4
+ "description": "PHP preprocessor for the Kirigami static site generator. Compile PHP page templates to clean, deployable HTML — with zero server dependency.",
5
+ "keywords": [
6
+ "kirigami",
7
+ "php",
8
+ "preprocessor",
9
+ "static-site-generator",
10
+ "ssg",
11
+ "wasm",
12
+ "php-wasm",
13
+ "markdown",
14
+ "yaml",
15
+ "github-pages",
16
+ "pages"
17
+ ],
18
+ "license": "GPL-3.0-or-later",
19
+ "author": "Maxime Larrivée-Roy",
20
+ "type": "module",
21
+ "main": "index.js",
22
+ "types": "index.d.ts",
23
+ "files": [
24
+ "index.js",
25
+ "index.d.ts",
26
+ "src/",
27
+ "LICENSE",
28
+ "README.md"
29
+ ],
30
+ "engines": {
31
+ "node": ">=24.0.0",
32
+ "npm": ">=10.2.3"
33
+ },
34
+ "exports": {
35
+ ".": {
36
+ "import": "./index.js"
37
+ },
38
+ "./package.json": "./package.json"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "scripts": {
44
+ "test": "node --test --test-concurrency=1 \"test/*.test.js\""
45
+ },
46
+ "dependencies": {
47
+ "@kirigami/php-wasm": "8.5.11-1",
48
+ "@kirigami/struct-walker": "1.0.6",
49
+ "picomatch": "^4.0.7"
50
+ },
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "git+https://github.com/php-kirigami/kirigami.git"
54
+ },
55
+ "homepage": "https://php-kirigami.github.io",
56
+ "bugs": {
57
+ "url": "https://github.com/php-kirigami/kirigami/issues"
58
+ }
59
+ }
@@ -25,6 +25,7 @@ class HTML
25
25
  'code', 'dfn', 'em', 'i', 'img', 'input', 'kbd', 'label', 'map',
26
26
  'mark', 'object', 'output', 'q', 's', 'samp', 'select', 'small',
27
27
  'span', 'strong', 'sub', 'sup', 'textarea', 'time', 'tt', 'u', 'var',
28
+ 'bdi', 'data', 'del', 'font', 'ins', 'rp', 'rt', 'ruby', 'strike', 'wbr',
28
29
  ];
29
30
 
30
31
  // The HTML namespace URI Lexbor assigns to plain HTML elements (foreign
@@ -188,20 +189,63 @@ class HTML
188
189
  }
189
190
 
190
191
  $inner = '';
191
- foreach ($children as $child) {
192
- $inner .= static::renderNode($child, $depth + 1);
192
+ foreach (static::groupInlineRuns($children) as $group) {
193
+ if (is_array($group)) {
194
+ // Text and inline elements that follow each other: one line, so
195
+ // the spaces between them survive ("<b>bold</b>, next").
196
+ $inner .= str_repeat(' ', ($depth + 1) * self::INDENT) . trim(static::renderInlineNodes($group)) . "\n";
197
+ continue;
198
+ }
199
+ $inner .= static::renderNode($group, $depth + 1);
193
200
  }
194
201
 
195
202
  return "{$pad}<{$tag}{$attrs}>\n{$inner}{$pad}</{$tag}>\n";
196
203
  }
197
204
 
205
+ // Splits a block's children into single nodes and runs (arrays) of
206
+ // consecutive text/inline nodes that contain real text. A run without text
207
+ // (a row of <a><img></a>, say) stays as separate nodes, one per line.
208
+ private static function groupInlineRuns(array $children): array
209
+ {
210
+ $groups = [];
211
+ $run = [];
212
+ $flush = static function () use (&$groups, &$run) {
213
+ $hasText = false;
214
+ foreach ($run as $node) {
215
+ if ($node->nodeType === XML_TEXT_NODE && trim($node->nodeValue) !== '') $hasText = true;
216
+ }
217
+ if ($hasText) $groups[] = $run;
218
+ else foreach ($run as $node) $groups[] = $node;
219
+ $run = [];
220
+ };
221
+ foreach ($children as $child) {
222
+ $isInline = $child->nodeType === XML_TEXT_NODE
223
+ || ($child->nodeType === XML_ELEMENT_NODE
224
+ && static::isInline($child)
225
+ && static::hasOnlyInlineChildren($child));
226
+ if ($isInline) {
227
+ $run[] = $child;
228
+ } else {
229
+ $flush();
230
+ $groups[] = $child;
231
+ }
232
+ }
233
+ $flush();
234
+ return $groups;
235
+ }
236
+
198
237
  // Serializes a node's inline content on a single line, collapsing any run
199
238
  // of spaces/tabs/newlines in the source text to a single space (equivalent
200
239
  // to HTML's whitespace-collapsing behavior).
201
240
  private static function renderInline(Dom\Node $node): string
241
+ {
242
+ return static::renderInlineNodes($node->childNodes);
243
+ }
244
+
245
+ private static function renderInlineNodes(iterable $nodes): string
202
246
  {
203
247
  $out = '';
204
- foreach ($node->childNodes as $child) {
248
+ foreach ($nodes as $child) {
205
249
  if ($child->nodeType === XML_TEXT_NODE) {
206
250
  $text = preg_replace('/\s+/', ' ', $child->nodeValue);
207
251
  $out .= htmlspecialchars($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
@@ -244,6 +288,14 @@ class HTML
244
288
  return $elementCount <= 1;
245
289
  }
246
290
 
291
+ // A known inline element, or a custom element (its name always has a
292
+ // hyphen), which browsers lay out inline unless a stylesheet says otherwise.
293
+ private static function isInline(Dom\Node $node): bool
294
+ {
295
+ $name = strtolower($node->nodeName);
296
+ return in_array($name, self::INLINE, true) || str_contains($name, '-');
297
+ }
298
+
247
299
  // Checks that every direct descendant is inline (text, inline void, inline elements)
248
300
  // The inline elements themselves must not contain block elements
249
301
  private static function hasOnlyInlineChildren(Dom\Node $node): bool
@@ -255,7 +307,7 @@ class HTML
255
307
  if ($child->nodeType !== XML_ELEMENT_NODE) {
256
308
  return false;
257
309
  }
258
- if (!in_array(strtolower($child->nodeName), self::INLINE, true)) {
310
+ if (!static::isInline($child)) {
259
311
  return false;
260
312
  }
261
313
  // Recursive: the inline element must not contain block elements