@jxsuite/compiler 0.25.2 → 0.25.4

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@jxsuite/compiler",
3
- "version": "0.25.2",
3
+ "version": "0.25.4",
4
4
  "description": "Jx static HTML compiler, island detector, and site builder",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -41,9 +41,9 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@apidevtools/json-schema-ref-parser": "^15.3.5",
44
- "@jxsuite/parser": "^0.25.2",
45
- "@jxsuite/runtime": "^0.25.2",
46
- "@jxsuite/schema": "^0.25.1",
44
+ "@jxsuite/parser": "^0.25.4",
45
+ "@jxsuite/runtime": "^0.25.4",
46
+ "@jxsuite/schema": "^0.25.4",
47
47
  "remark-gfm": "^4.0.1",
48
48
  "remark-stringify": "^11.0.0",
49
49
  "sharp": "^0.34.5",
@@ -2,7 +2,7 @@
2
2
  * Image-cache.js — Content-hash based cache for processed image variants.
3
3
  *
4
4
  * Stores a manifest of previously processed images so that unchanged sources can skip re-encoding
5
- * on subsequent builds. Cache lives in .jx-cache/images/.
5
+ * on subsequent builds. Cache lives in .cache/images/.
6
6
  */
7
7
 
8
8
  import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
@@ -41,7 +41,7 @@ export function cacheKey(srcPath: string, config: ImageConfig) {
41
41
  * @returns {CacheManifest}
42
42
  */
43
43
  export function loadCache(projectRoot: string) {
44
- const manifestPath = resolve(projectRoot, ".jx-cache/images/manifest.json");
44
+ const manifestPath = resolve(projectRoot, ".cache/images/manifest.json");
45
45
  if (!existsSync(manifestPath)) {
46
46
  return { version: 1, entries: {} };
47
47
  }
@@ -59,7 +59,7 @@ export function loadCache(projectRoot: string) {
59
59
  * @param {CacheManifest} cache
60
60
  */
61
61
  export function saveCache(projectRoot: string, cache: CacheManifest) {
62
- const cacheDir = resolve(projectRoot, ".jx-cache/images");
62
+ const cacheDir = resolve(projectRoot, ".cache/images");
63
63
  mkdirSync(cacheDir, { recursive: true });
64
64
  writeFileSync(resolve(cacheDir, "manifest.json"), JSON.stringify(cache, null, 2), "utf8");
65
65
  }
@@ -8,6 +8,7 @@
8
8
  import { createHash } from "node:crypto";
9
9
  import { readFileSync, mkdirSync, existsSync } from "node:fs";
10
10
  import { resolve, basename, extname } from "node:path";
11
+ import { createRequire } from "node:module";
11
12
 
12
13
  export interface ImageVariant {
13
14
  width: number; // Pixel width of the variant
@@ -35,9 +36,22 @@ let _sharp: typeof import("sharp") | null = null;
35
36
 
36
37
  async function getSharp() {
37
38
  if (_sharp) return _sharp;
39
+ // Primary: dynamic import — works in tests (mock.module intercepts it) and in
40
+ // production installs where @img/sharp-* native packages are adjacent to cli.js.
38
41
  try {
39
42
  const sharpMod = await import("sharp");
40
- _sharp = sharpMod.default;
43
+ _sharp = sharpMod.default as typeof import("sharp");
44
+ return _sharp;
45
+ } catch {
46
+ // Fall through to CJS fallback below.
47
+ }
48
+ // Fallback: resolve from the project being compiled. This covers symlinked
49
+ // monorepo dev environments (e.g. NixOS) where Node.js resolves import.meta.url
50
+ // to the compiler package's real path, making the @img/sharp-* packages
51
+ // unreachable via the primary import path.
52
+ try {
53
+ const req = createRequire(resolve(process.cwd(), "package.json"));
54
+ _sharp = req("sharp") as typeof import("sharp");
41
55
  return _sharp;
42
56
  } catch (e) {
43
57
  throw new Error(
@@ -93,7 +93,8 @@ export async function buildSite(
93
93
  const hasOptimized = existsSync(optimizedDir);
94
94
  let tmpOptimized = "";
95
95
  if (hasOptimized) {
96
- tmpOptimized = resolve(projectRoot, ".jx-cache/_optimized_tmp");
96
+ tmpOptimized = resolve(projectRoot, ".cache/_optimized_tmp");
97
+ mkdirSync(resolve(projectRoot, ".cache"), { recursive: true });
97
98
  renameSync(optimizedDir, tmpOptimized);
98
99
  }
99
100
  rmSync(outDir, { recursive: true, force: true });
@@ -624,6 +625,16 @@ function expandMapTemplate(template: JxMutableNode, scope: Record<string, unknow
624
625
  }
625
626
  }
626
627
  node.attributes = attrs;
628
+ } else if (k === "$props" && v && typeof v === "object") {
629
+ const props = { ...v } as Record<string, unknown>;
630
+ for (const [pk, pv] of Object.entries(props)) {
631
+ if (typeof pv === "string" && isTemplateString(pv)) {
632
+ const resolved = evaluateMapTemplate(pv, scope);
633
+ // null = evaluation error → keep template string; undefined = missing data → use null
634
+ props[pk] = resolved !== null ? (resolved ?? null) : pv;
635
+ }
636
+ }
637
+ node.$props = props;
627
638
  } else if (typeof v === "string" && isTemplateString(v)) {
628
639
  node[k] = evaluateMapTemplate(v, scope) ?? v;
629
640
  } else {
@@ -694,6 +705,13 @@ function resolveDocTemplates(node: JxElement | string, scope: Record<string, unk
694
705
  }
695
706
  }
696
707
  }
708
+ if (node.$props && typeof node.$props === "object") {
709
+ for (const [k, v] of Object.entries(node.$props)) {
710
+ if (typeof v === "string" && isTemplateString(v)) {
711
+ node.$props[k] = evaluateStaticTemplate(v, scope) ?? v;
712
+ }
713
+ }
714
+ }
697
715
  const rawChildren = node.children as unknown;
698
716
  if (
699
717
  rawChildren &&