@jxsuite/compiler 1.1.0 → 1.3.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.
@@ -41,6 +41,12 @@ import type {
41
41
  export interface CompileElementOptions {
42
42
  /** Resolve an `$elements` ref path to its emitted JS module path. */
43
43
  resolveElementPath?: (refPath: string, currentDir: string | null) => string;
44
+ /**
45
+ * Rewrite a Function-def `$src` specifier to its served URL (bundleable specifiers → their
46
+ * `/assets/` bundle path). Receives the directory of the declaring document for relative
47
+ * specifiers. Identity when omitted.
48
+ */
49
+ rewriteSrc?: (specifier: string, docDir: string | null) => string;
44
50
  $media?: Record<string, string>;
45
51
  formats?: FormatRegistry;
46
52
  basePath?: string | null;
@@ -135,7 +141,13 @@ export async function compileElement(
135
141
  if (optsMedia) {
136
142
  doc.$media = { ...optsMedia, ...doc.$media };
137
143
  }
138
- const jsContent = emitElementModule(doc, className, elementImports);
144
+ const { rewriteSrc } = opts;
145
+ const jsContent = emitElementModule(
146
+ doc,
147
+ className,
148
+ elementImports,
149
+ rewriteSrc ? (spec: string) => rewriteSrc(spec, currentDir) : undefined,
150
+ );
139
151
  const outputPath = filePath ? filePath.replace(/\.json$/, ".js") : `${tagName}.js`;
140
152
  files.push({ content: jsContent, path: outputPath, tagName });
141
153
  }
@@ -244,7 +256,12 @@ function extractInitialValue(def: JxMutableNode) {
244
256
  * @param {string[]} elementImports
245
257
  * @returns {string}
246
258
  */
247
- export function emitElementModule(doc: JxDocument, className: string, elementImports: string[]) {
259
+ export function emitElementModule(
260
+ doc: JxDocument,
261
+ className: string,
262
+ elementImports: string[],
263
+ rewriteSrc?: (specifier: string) => string,
264
+ ) {
248
265
  const lines: string[] = ["// Generated by @jxsuite/compiler — do not edit manually"];
249
266
 
250
267
  if (doc.$id) {
@@ -269,7 +286,10 @@ export function emitElementModule(doc: JxDocument, className: string, elementImp
269
286
  }
270
287
  }
271
288
  for (const [srcPath, names] of srcImportMap) {
272
- lines.push(`import { ${names.join(", ")} } from '${srcPath}';`);
289
+ // Bundleable specifiers (npm:…, ./relative) are rewritten to their /assets/ bundle URL;
290
+ // The site build bundles them after all documents compile (spec.md §12).
291
+ const importPath = rewriteSrc ? rewriteSrc(srcPath) : srcPath;
292
+ lines.push(`import { ${names.join(", ")} } from '${importPath}';`);
273
293
  }
274
294
 
275
295
  lines.push(
@@ -486,11 +506,16 @@ export function emitElementModule(doc: JxDocument, className: string, elementImp
486
506
  );
487
507
  }
488
508
  lines.push(
509
+ // Lifecycle: onMount (spec §16.4) — same microtask contract as the runtime
510
+ " if (typeof this.state.onMount === 'function') {",
511
+ " queueMicrotask(() => this.state.onMount(this.state));",
512
+ " }",
489
513
  " }",
490
514
  "",
491
515
  // DisconnectedCallback
492
516
  " disconnectedCallback() {",
493
517
  " if (this.#dispose) { this.#dispose(); this.#dispose = null; }",
518
+ " if (typeof this.state.onUnmount === 'function') { this.state.onUnmount(this.state); }",
494
519
  " }",
495
520
  "}",
496
521
  "",
@@ -7,10 +7,12 @@
7
7
 
8
8
  import {
9
9
  buildAttrs,
10
+ colorSchemePrePaintScript,
10
11
  compileStyles,
11
12
  createCompileContext,
12
13
  escapeHtml,
13
14
  isNodeDynamic,
15
+ pureSchemeOf,
14
16
  resolveStaticValue,
15
17
  SELF_CLOSING,
16
18
  } from "../shared.ts";
@@ -31,6 +33,7 @@ export function compileStaticPage(
31
33
  reactivitySrc?: string;
32
34
  litHtmlSrc?: string;
33
35
  projectStyle?: JxStyle | null;
36
+ prePaintScheme?: boolean;
34
37
  [key: string]: unknown;
35
38
  },
36
39
  ) {
@@ -51,7 +54,12 @@ export function compileStaticPage(
51
54
  let moduleScripts = "";
52
55
  if (islands.length > 0) {
53
56
  for (const island of islands) {
54
- const moduleContent = emitElementModule(island.def as JxDocument, island.className, []);
57
+ const moduleContent = emitElementModule(
58
+ island.def as JxDocument,
59
+ island.className,
60
+ [],
61
+ opts.rewriteSrc as ((specifier: string) => string) | undefined,
62
+ );
55
63
  files.push({
56
64
  content: moduleContent,
57
65
  path: `_islands/${island.tagName}.js`,
@@ -73,13 +81,20 @@ export function compileStaticPage(
73
81
  .join("\n ");
74
82
  }
75
83
 
84
+ // Forced-scheme contract (spec §9.5): restore the persisted scheme before any styles apply
85
+ const prePaint =
86
+ opts.prePaintScheme !== false &&
87
+ Object.values(raw.$media ?? {}).some((q) => pureSchemeOf(String(q)) !== null)
88
+ ? `<script>${colorSchemePrePaintScript()}</script>\n `
89
+ : "";
90
+
76
91
  const html = `<!DOCTYPE html>
77
92
  <html lang="en">
78
93
  <head>
79
94
  <meta charset="utf-8">
80
95
  <meta name="viewport" content="width=device-width, initial-scale=1">
81
96
  <title>${escapeHtml(title)}</title>
82
- ${importMap}
97
+ ${prePaint}${importMap}
83
98
  ${styleBlock}
84
99
  </head>
85
100
  <body>