@kirigami/php-prepros 1.9.3 → 3.0.0

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/index.d.ts CHANGED
@@ -9,19 +9,19 @@
9
9
  *
10
10
  * @example
11
11
  * ```js
12
- * import { render, sitemap, runenv, mountPath } from '@kirigami/php-prepros';
12
+ * import { render, sitemap, runenv, mountPath, processImages } from '@kirigami/php-prepros';
13
13
  *
14
14
  * // Compile a single page
15
- * const result = await render('src/index.php');
15
+ * const page = await render('_index.php');
16
16
  *
17
17
  * // Compile every page in the source directory
18
- * const result = await render('src/');
18
+ * const tree = await render('.');
19
19
  *
20
20
  * // Generate sitemap.xml
21
- * const sitemap = await sitemap();
21
+ * const sitemapResult = await sitemap();
22
22
  *
23
23
  * // Run an arbitrary PHP script in the same sandboxed environment
24
- * const result = await runenv('scripts/purge-cache.php');
24
+ * const purgeResult = await runenv('scripts/purge-cache.php');
25
25
  *
26
26
  * // Mount a local file/directory into the sandbox before rendering
27
27
  * await mountPath('assets/data/team.yaml');
@@ -40,7 +40,7 @@
40
40
  // ---------------------------------------------------------------------------
41
41
 
42
42
  /**
43
- * Returned by every prepros operation.
43
+ * Returned by render, sitemap and runenv; image batches extend this shape.
44
44
  */
45
45
  export interface PreprosResult {
46
46
  /** `true` when the operation completed without errors. */
@@ -50,17 +50,23 @@ export interface PreprosResult {
50
50
  * Paths of every file written to disk by this operation (relative to the
51
51
  * project root). Includes the compiled HTML page(s) and any side-effect
52
52
  * files such as `.cache.db` or resized images produced by `IMG::save()`.
53
+ * May be absent if result parsing fails.
53
54
  */
54
- files: string[];
55
+ files?: string[];
55
56
 
56
57
  /** Human-readable error message. Only present when `success` is `false`. */
57
58
  error?: string;
58
59
 
59
- /**
60
- * Raw PHP stdout / stderr, useful for debugging.
61
- * Only present when response parsing fails.
62
- */
63
- response?: string;
60
+ /** Captured PHP stdout. */
61
+ debug?: string;
62
+ /** PHP diagnostics attached to failure results. */
63
+ stderr?: string;
64
+ /** Nonfatal PHP diagnostics on a successful operation. */
65
+ warnings?: string;
66
+ /** Render failure context, when available. */
67
+ page?: string | null;
68
+ /** PHP source location, when available. */
69
+ where?: string;
64
70
  }
65
71
 
66
72
 
@@ -93,21 +99,24 @@ export interface PreprosResult {
93
99
  * Any `@tag filename` annotation whose extension is `.yaml`, `.yml`,
94
100
  * `.json`, or `.md` is automatically loaded and made available as a PHP
95
101
  * variable with the same name as the tag. Remote URLs are supported when
96
- * `network: true` is set in `kirigami.yaml`.
102
+ * `prepros.network: true` is set in `kirigami.yaml`.
97
103
  *
98
104
  * @param file Path to a `.php` source file or a directory, relative to the
99
- * project root. Defaults to `.` (the entire source tree).
105
+ * configured `kirigami.root`. Defaults to `.` (the entire source tree).
100
106
  *
107
+ * @param phpIncludes Local plugin PHP files to mount and include before rendering.
108
+ * Missing files are skipped; defaults to an empty list.
101
109
  * @returns A {@link PreprosResult} describing what was written.
102
110
  *
103
111
  * @throws When the `kirigami.yaml` config is missing or malformed.
104
112
  * @throws When `kirigami.root` does not exist on disk.
105
113
  */
106
- export function render(file?: string): Promise<PreprosResult>;
114
+ export function render(file?: string, phpIncludes?: string[]): Promise<PreprosResult>;
107
115
 
108
116
 
109
117
  /**
110
- * Generate a `sitemap.xml` at the source root.
118
+ * Generate sitemap.xml and robots.txt at the source root, plus humans.txt
119
+ * when configured author data provides content.
111
120
  *
112
121
  * Scans every `_index.php` found in the source tree and produces a
113
122
  * standard Sitemaps 0.9 XML document. Priority is calculated from depth
@@ -118,7 +127,7 @@ export function render(file?: string): Promise<PreprosResult>;
118
127
  * @returns A {@link PreprosResult} with `files` containing the path to the
119
128
  * generated `sitemap.xml`.
120
129
  */
121
- export function sitemap(dir?: string): Promise<PreprosResult>;
130
+ export function sitemap(): Promise<PreprosResult>;
122
131
 
123
132
 
124
133
  /**
@@ -133,19 +142,19 @@ export function sitemap(dir?: string): Promise<PreprosResult>;
133
142
  *
134
143
  * ```js
135
144
  * // Run a standalone PHP script
136
- * const result = await runenv('scripts/purge-cache.php');
145
+ * const purgeResult = await runenv('scripts/purge-cache.php');
137
146
  *
138
147
  * // Also mount extra local paths/files into the sandbox before running
139
- * const result = await runenv('scripts/build-og-images.php', ['assets/photos']);
148
+ * const imageResult = await runenv('scripts/build-og-images.php', ['assets/photos/hero.jpg']);
140
149
  *
141
150
  * // Extra arguments are appended and available as $argv[2], $argv[3], … in the script
142
- * const result = await runenv('scripts/import.php', [], '--force');
151
+ * const importResult = await runenv('scripts/import.php', [], '--force');
143
152
  * ```
144
153
  *
145
154
  * @param script Path to a PHP file inside the project, executed with
146
155
  * `require_once`.
147
- * @param paths Extra local paths (files or directories) to mount into the
148
- * sandbox before the script runs.
156
+ * @param paths Extra project files to mount before execution. Missing files
157
+ * are skipped. Use mountPath() separately for directories.
149
158
  * @param args Extra string arguments appended to the script's `$argv`.
150
159
  *
151
160
  * @returns A {@link PreprosResult} describing what was written. Call
@@ -153,11 +162,29 @@ export function sitemap(dir?: string): Promise<PreprosResult>;
153
162
  * listed in `result.files`.
154
163
  *
155
164
  * @throws When no `script` path is given.
156
- * @throws When `script` resolves outside the project root, or doesn't exist.
165
+ * @throws When the script is missing, an input is a directory, or any input
166
+ * escapes the project lexically or through a symbolic link.
157
167
  */
158
168
  export function runenv(script: string, paths?: string[], ...args: string[]): Promise<PreprosResult>;
159
169
 
160
170
 
171
+ /**
172
+ * Like {@link runenv}, for a script shipped inside a plugin package. A linked
173
+ * or workspace plugin lives outside the project, so the script is contained
174
+ * by `pluginRoot` instead, and mounted under `/plugin-scripts/<package dir>/`.
175
+ * The caller must pass the resolved package directory of an active plugin.
176
+ *
177
+ * @param script Path of the PHP script, absolute or relative to `pluginRoot`.
178
+ * @param pluginRoot The plugin's package directory.
179
+ * @param paths Extra project files to mount, as for {@link runenv}.
180
+ * @param args Extra string arguments appended to the script's `$argv`.
181
+ *
182
+ * @throws When the script is missing, is a directory, or escapes
183
+ * `pluginRoot` lexically or through a symbolic link.
184
+ */
185
+ export function runPluginScript(script: string, pluginRoot: string, paths?: string[], ...args: string[]): Promise<PreprosResult>;
186
+
187
+
161
188
  /**
162
189
  * The JavaScript-side counterpart to `PREPROS::mount()`. Mounts a local
163
190
  * file or directory — recursively, preserving structure — into the WASM
@@ -182,11 +209,18 @@ export function runenv(script: string, paths?: string[], ...args: string[]): Pro
182
209
  * @param virtualDir Destination path inside the WASM filesystem. Defaults
183
210
  * to `/project/<localPath relative to the project root>`
184
211
  * when omitted.
185
- * @param php WASM PHP instance to mount into. Defaults to the shared
186
- * singleton instance (creating it if needed).
212
+ * @param php WASM PHP instance to mount into. Defaults to PHP-prepros's
213
+ * owned instance (creating it if needed).
187
214
  */
188
215
  export function mountPath(localPath: string, virtualDir?: string, php?: unknown): Promise<void>;
189
216
 
217
+ /**
218
+ * Waits for queued PHP operations, disposes the owned runtime and clears its
219
+ * cached configuration and mounts. The next operation creates a fresh runtime.
220
+ * Project.reload() also invalidates core's plugin PHP include list.
221
+ */
222
+ export function resetRuntime(): Promise<void>;
223
+
190
224
 
191
225
  /**
192
226
  * A single unit of work for {@link processImages}.
@@ -230,6 +264,8 @@ export type ImageJob =
230
264
  * every image written back to the host, plus the palettes that were requested.
231
265
  */
232
266
  export interface ImageBatchResult extends PreprosResult {
267
+ /** Always normalized to an array, including on failure. */
268
+ files: string[];
233
269
  /** Extracted palettes, keyed `"<src>:<count>"`, each a list of `#rrggbb`. */
234
270
  colors: Record<string, string[]>;
235
271
  }
@@ -249,4 +285,4 @@ export interface ImageBatchResult extends PreprosResult {
249
285
  * @returns An {@link ImageBatchResult}. Resized files are also copied to the
250
286
  * host at the project-relative equivalent of each `dests` entry.
251
287
  */
252
- export function processImages(jobs?: ImageJob[]): Promise<ImageBatchResult>;
288
+ export function processImages(jobs?: ImageJob[]): Promise<ImageBatchResult>;
package/index.js CHANGED
@@ -1 +1 @@
1
- export { render, sitemap, runenv, mountPath, processImages } from "./src/prepros.js";
1
+ export { render, sitemap, runenv, runPluginScript, mountPath, processImages, resetRuntime } from "./src/prepros.js";
package/package.json CHANGED
@@ -1,59 +1,59 @@
1
- {
2
- "name": "@kirigami/php-prepros",
3
- "version": "1.9.3",
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": "MIT",
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": "echo \"Error: no test specified\" && exit 1"
45
- },
46
- "dependencies": {
47
- "@kirigami/php-wasm": "8.5.10-5",
48
- "@kirigami/struct-walker": "1.0.5",
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.0.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",
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,67 +1,68 @@
1
- <?php
2
-
3
- /**
4
- * Batch image worker for the Kirigami build pipeline.
5
- *
6
- * Driven by @kirigami/kirigami's `sass` task (see processImages() in
7
- * prepros.js): it receives a JSON list of jobs on $argv[2] and runs them
8
- * through the IMG class (GD, with the Imagick fallback) so that the Sass
9
- * `img-asset()` / `colors()` functions and the PHP `IMG::asset()` /
10
- * `<img asset>` tag all share one engine.
11
- *
12
- * Job shapes:
13
- * { "op": "resize", "src": "hero.jpg", "width": 800, "height": 0,
14
- * "cover": false, "quality": 82,
15
- * "dests": ["/project/dist/images/hero-800w.webp",
16
- * "/project/src/images/hero-800w.webp"] }
17
- * { "op": "palette", "src": "hero.jpg", "count": 5 }
18
- *
19
- * `src` is resolved against `image.source`; `dests` are absolute virtual
20
- * paths already carrying the target extension. Staleness is decided on the
21
- * JS side, so every job listed here is meant to run. Generated files are
22
- * returned through PREPROS::exportFile() (STD::succeed copies them back to
23
- * the host); extracted palettes ride back in the `colors` map.
24
- */
25
-
26
- include(__DIR__ . '/utils.inc.php');
27
-
28
- try {
29
-
30
- $jobs = json_decode($argv[2] ?? '[]');
31
- if (!is_array($jobs)) throw new Exception("Invalid jobs payload.");
32
-
33
- $colors = [];
34
-
35
- foreach ($jobs as $job) {
36
-
37
- if (($job->op ?? '') === 'palette') {
38
- $count = (int) ($job->count ?? 5);
39
- $colors[$job->src . ':' . $count] = IMG::palette($job->src, $count);
40
- continue;
41
- }
42
-
43
- // op: resize
44
- $srcfile = FS::pathJoin(PREPROS::$config->image->source, $job->src);
45
- if (!$mounted = PREPROS::mount($srcfile)) throw new Exception("Can't mount image: {$job->src}");
46
- $localfile = current($mounted);
47
- if (!is_file($localfile)) throw new Exception("Can't mount image: {$job->src}");
48
-
49
- $width = (int) ($job->width ?? 0);
50
- $height = (int) ($job->height ?? 0);
51
- $cover = (bool) ($job->cover ?? false);
52
- $quality = isset($job->quality) ? (int) $job->quality : null;
53
-
54
- $img = new IMG($localfile);
55
- if ($width && $height) $img->resize($width, $height, $cover);
56
- elseif ($width) $img->resize($width);
57
- elseif ($height) $img->resize((int) round($img->width * $height / $img->height), $height);
58
- // neither: no resize, just re-encode to the target format
59
-
60
- foreach ($job->dests as $dest) $img->save($dest, $quality);
61
- }
62
-
63
- STD::succeed(['files' => PREPROS::getExportedFiles(), 'colors' => $colors]);
64
-
65
- } catch (Throwable $e) {
66
- STD::error($e->getMessage());
67
- }
1
+ <?php
2
+
3
+ /**
4
+ * Batch image worker for the Kirigami build pipeline.
5
+ *
6
+ * Driven by @kirigami/kirigami's `sass` task (see processImages() in
7
+ * prepros.js): it receives a JSON list of jobs on $argv[2] and runs them
8
+ * through the IMG class (GD, with the Imagick fallback) so that the Sass
9
+ * `img-asset()` / `colors()` functions and the PHP `IMG::asset()` /
10
+ * `<img asset>` tag all share one engine.
11
+ *
12
+ * Job shapes:
13
+ * { "op": "resize", "src": "hero.jpg", "width": 800, "height": 0,
14
+ * "cover": false, "quality": 82,
15
+ * "dests": ["/project/dist/images/hero-800w.webp",
16
+ * "/project/src/images/hero-800w.webp"] }
17
+ * { "op": "palette", "src": "hero.jpg", "count": 5 }
18
+ *
19
+ * `src` is resolved against `image.source`; `dests` are absolute virtual
20
+ * paths already carrying the target extension. Staleness is decided on the
21
+ * JS side, so every job listed here is meant to run. Generated files are
22
+ * returned through PREPROS::exportFile() (STD::succeed copies them back to
23
+ * the host); extracted palettes ride back in the `colors` map.
24
+ */
25
+
26
+ // Framework bootstrap (autoloader, $argv/$config, aliases, `boot` hook) is
27
+ // loaded via php.ini's auto_prepend_file, not an explicit include here.
28
+
29
+ try {
30
+
31
+ $jobs = json_decode($argv[2] ?? '[]');
32
+ if (!is_array($jobs)) throw new Exception("Invalid jobs payload.");
33
+
34
+ $colors = [];
35
+
36
+ foreach ($jobs as $job) {
37
+
38
+ if (($job->op ?? '') === 'palette') {
39
+ $count = (int) ($job->count ?? 5);
40
+ $colors[$job->src . ':' . $count] = IMG::palette($job->src, $count);
41
+ continue;
42
+ }
43
+
44
+ // op: resize
45
+ $srcfile = FS::pathJoin(PREPROS::$config->image->source, $job->src);
46
+ if (!$mounted = PREPROS::mount($srcfile)) throw new Exception("Can't mount image: {$job->src}");
47
+ $localfile = current($mounted);
48
+ if (!is_file($localfile)) throw new Exception("Can't mount image: {$job->src}");
49
+
50
+ $width = (int) ($job->width ?? 0);
51
+ $height = (int) ($job->height ?? 0);
52
+ $cover = (bool) ($job->cover ?? false);
53
+ $quality = isset($job->quality) ? (int) $job->quality : null;
54
+
55
+ $img = new IMG($localfile);
56
+ if ($width && $height) $img->resize($width, $height, $cover);
57
+ elseif ($width) $img->resize($width);
58
+ elseif ($height) $img->resize((int) round($img->width * $height / $img->height), $height);
59
+ // neither: no resize, just re-encode to the target format
60
+
61
+ foreach ($job->dests as $dest) $img->save($dest, $quality);
62
+ }
63
+
64
+ STD::succeed(['files' => PREPROS::getExportedFiles(), 'colors' => $colors]);
65
+
66
+ } catch (Throwable $e) {
67
+ STD::error($e->getMessage());
68
+ }