@kirigami/php-prepros 1.2.0 → 1.6.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/index.d.ts CHANGED
@@ -25,6 +25,12 @@
25
25
  *
26
26
  * // Mount a local file/directory into the sandbox before rendering
27
27
  * await mountPath('assets/data/team.yaml');
28
+ *
29
+ * // Resize images / extract palettes through the IMG class (GD + Imagick)
30
+ * const { files, colors } = await processImages([
31
+ * { op: 'resize', src: 'hero.jpg', width: 1200, dests: ['/project/src/images/hero-1200w.webp'] },
32
+ * { op: 'palette', src: 'hero.jpg', count: 5 },
33
+ * ]);
28
34
  * ```
29
35
  */
30
36
 
@@ -149,34 +155,98 @@ export function sitemap(dir?: string): Promise<PreprosResult>;
149
155
  * @throws When no `script` path is given.
150
156
  * @throws When `script` resolves outside the project root, or doesn't exist.
151
157
  */
152
- export function runenv(script: string, paths?: string[], ...args: string[]): Promise<PreprosResult>;
153
-
154
-
155
- /**
156
- * The JavaScript-side counterpart to `PREPROS::mount()`. Mounts a local
157
- * file or directory — recursively, preserving structure — into the WASM
158
- * sandbox's virtual filesystem, ahead of (or between) calls to
159
- * {@link render}, {@link sitemap}, or {@link runenv}.
160
- *
161
- * Mounting a directory only copies files whose extension is one of the
162
- * defaults (`.php`, `.json`, `.yaml`, `.yml`, `.md`, `.db`, `.txt`) or
163
- * listed in `prepros.mountext`, same as automatic root mounting. Mounting a
164
- * single file directly copies it regardless of extension.
165
- *
166
- * ```js
167
- * // Mount a single file at its natural virtual path (/project/<relative path>)
168
- * await mountPath('assets/data/team.yaml');
169
- *
170
- * // Mount a whole directory, at a custom virtual path
171
- * await mountPath('vendor/fonts', '/project/fonts');
172
- * ```
173
- *
174
- * @param localPath Path to a local file or directory. Relative paths are
175
- * resolved against the project root.
176
- * @param virtualDir Destination path inside the WASM filesystem. Defaults
177
- * to `/project/<localPath relative to the project root>`
178
- * when omitted.
179
- * @param php WASM PHP instance to mount into. Defaults to the shared
180
- * singleton instance (creating it if needed).
181
- */
182
- export function mountPath(localPath: string, virtualDir?: string, php?: unknown): Promise<void>;
158
+ export function runenv(script: string, paths?: string[], ...args: string[]): Promise<PreprosResult>;
159
+
160
+
161
+ /**
162
+ * The JavaScript-side counterpart to `PREPROS::mount()`. Mounts a local
163
+ * file or directory — recursively, preserving structure — into the WASM
164
+ * sandbox's virtual filesystem, ahead of (or between) calls to
165
+ * {@link render}, {@link sitemap}, or {@link runenv}.
166
+ *
167
+ * Mounting a directory only copies files whose extension is one of the
168
+ * defaults (`.php`, `.json`, `.yaml`, `.yml`, `.md`, `.db`, `.txt`) or
169
+ * listed in `prepros.mountext`, same as automatic root mounting. Mounting a
170
+ * single file directly copies it regardless of extension.
171
+ *
172
+ * ```js
173
+ * // Mount a single file at its natural virtual path (/project/<relative path>)
174
+ * await mountPath('assets/data/team.yaml');
175
+ *
176
+ * // Mount a whole directory, at a custom virtual path
177
+ * await mountPath('vendor/fonts', '/project/fonts');
178
+ * ```
179
+ *
180
+ * @param localPath Path to a local file or directory. Relative paths are
181
+ * resolved against the project root.
182
+ * @param virtualDir Destination path inside the WASM filesystem. Defaults
183
+ * to `/project/<localPath relative to the project root>`
184
+ * when omitted.
185
+ * @param php WASM PHP instance to mount into. Defaults to the shared
186
+ * singleton instance (creating it if needed).
187
+ */
188
+ export function mountPath(localPath: string, virtualDir?: string, php?: unknown): Promise<void>;
189
+
190
+
191
+ /**
192
+ * A single unit of work for {@link processImages}.
193
+ *
194
+ * - **`resize`** — decode `src` (resolved against `image.source`), optionally
195
+ * resize it, and encode a copy to every path in `dests` (each an absolute
196
+ * virtual path, e.g. `/project/src/images/hero-800w.webp`, already carrying
197
+ * the target extension). Omitting both `width` and `height` re-encodes at the
198
+ * source size. Staleness must be decided by the caller — every job passed in
199
+ * is executed.
200
+ * - **`palette`** — extract `count` representative colours from `src` via
201
+ * `IMG::palette()` (cached in `.cache.db`); returned in `colors`, not written.
202
+ */
203
+ export type ImageJob =
204
+ | {
205
+ op: "resize";
206
+ /** Source path, relative to `image.source` in `kirigami.yaml`. */
207
+ src: string;
208
+ /** Target width in px. `0`/omitted = derive from height (or keep). */
209
+ width?: number;
210
+ /** Target height in px. `0`/omitted = derive from width (or keep). */
211
+ height?: number;
212
+ /** Crop to fill instead of fitting inside `width`×`height`. */
213
+ cover?: boolean;
214
+ /** Encoder quality (0-100) for lossy formats. Defaults to 82. */
215
+ quality?: number;
216
+ /** Absolute virtual destination paths to write the encoded image to. */
217
+ dests: string[];
218
+ }
219
+ | {
220
+ op: "palette";
221
+ /** Source path, relative to `image.source` in `kirigami.yaml`. */
222
+ src: string;
223
+ /** Number of colours to extract. Defaults to 5. */
224
+ count?: number;
225
+ };
226
+
227
+
228
+ /**
229
+ * Result of {@link processImages}: a {@link PreprosResult} whose `files` lists
230
+ * every image written back to the host, plus the palettes that were requested.
231
+ */
232
+ export interface ImageBatchResult extends PreprosResult {
233
+ /** Extracted palettes, keyed `"<src>:<count>"`, each a list of `#rrggbb`. */
234
+ colors: Record<string, string[]>;
235
+ }
236
+
237
+
238
+ /**
239
+ * Run a batch of image jobs through the same `IMG` class (GD, with the Imagick
240
+ * fallback) used by `IMG::asset()` and the `<img asset>` tag.
241
+ *
242
+ * This is the engine behind `@kirigami/kirigami`'s Sass `img-asset()` and
243
+ * `colors()` functions: one implementation, one `image:` config, one set of
244
+ * output filenames across Sass, PHP and HTML — no native image dependency.
245
+ *
246
+ * @param jobs List of {@link ImageJob}s. An empty list is a no-op (the WASM
247
+ * runtime is not started).
248
+ *
249
+ * @returns An {@link ImageBatchResult}. Resized files are also copied to the
250
+ * host at the project-relative equivalent of each `dests` entry.
251
+ */
252
+ export function processImages(jobs?: ImageJob[]): Promise<ImageBatchResult>;
package/index.js CHANGED
@@ -1 +1 @@
1
- export { render, sitemap, runenv, mountPath } from "./src/prepros.js";
1
+ export { render, sitemap, runenv, mountPath, processImages } from "./src/prepros.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kirigami/php-prepros",
3
- "version": "1.2.0",
3
+ "version": "1.6.1",
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",
@@ -0,0 +1,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
+ 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
+ }