@jxsuite/compiler 0.28.2 → 0.28.3

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.28.2",
3
+ "version": "0.28.3",
4
4
  "description": "Jx static HTML compiler, island detector, and site builder",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -42,10 +42,10 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "@apidevtools/json-schema-ref-parser": "^15.3.5",
45
- "@jxsuite/parser": "^0.28.2",
46
- "@jxsuite/runtime": "^0.28.2",
47
- "@jxsuite/schema": "^0.28.2",
48
- "sharp": "^0.34.5"
45
+ "@jxsuite/parser": "^0.28.3",
46
+ "@jxsuite/runtime": "^0.28.3",
47
+ "@jxsuite/schema": "^0.28.3",
48
+ "sharp": "^0.35.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@happy-dom/global-registrator": "^20.10.2",
package/src/cli.ts CHANGED
@@ -10,7 +10,7 @@
10
10
  import { resolve } from "node:path";
11
11
 
12
12
  const args = process.argv.slice(2);
13
- const command = args[0];
13
+ const [command] = args;
14
14
 
15
15
  if (!command || command === "--help" || command === "-h") {
16
16
  console.log(`Usage: jx <command> [options]
@@ -27,9 +27,9 @@ Options:
27
27
  if (command === "build") {
28
28
  const rest = args.slice(1);
29
29
  const flags = new Set(rest.filter((a) => a.startsWith("--")));
30
- const positional = rest.filter((a) => !a.startsWith("--"));
30
+ const positional = rest.find((a) => !a.startsWith("--"));
31
31
 
32
- const projectRoot = resolve(positional[0] ?? ".");
32
+ const projectRoot = resolve(positional ?? ".");
33
33
  const verbose = flags.has("--verbose");
34
34
  const clean = !flags.has("--no-clean");
35
35
 
@@ -37,7 +37,7 @@ if (command === "build") {
37
37
 
38
38
  try {
39
39
  const { buildSite } = await import("./site/site-build.ts");
40
- const result = await buildSite(projectRoot, { verbose, clean });
40
+ const result = await buildSite(projectRoot, { clean, verbose });
41
41
 
42
42
  if (result.errors.length > 0) {
43
43
  console.error(`\nBuild completed with ${result.errors.length} error(s):`);
@@ -48,8 +48,8 @@ if (command === "build") {
48
48
  }
49
49
 
50
50
  console.log(`\nDone: ${result.routes} routes → ${result.files} files`);
51
- } catch (e) {
52
- const err = e as Error;
51
+ } catch (error) {
52
+ const err = error as Error;
53
53
  console.error(`Build failed: ${err.message}`);
54
54
  process.exit(1);
55
55
  }
@@ -1,10 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { runCli } from "./compiler.ts";
3
3
 
4
- const [, , src, out] = process.argv;
4
+ const [src, out] = process.argv.slice(2);
5
5
  if (src) {
6
- runCli(src, out).catch((err) => {
7
- console.error(err);
6
+ try {
7
+ await runCli(src, out);
8
+ } catch (error) {
9
+ console.error(error);
8
10
  process.exit(1);
9
- });
11
+ }
10
12
  }
package/src/compiler.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * jx-compiler.js — Compiler orchestrator
2
+ * Jx-compiler.js — Compiler orchestrator
3
3
  * @version 3.0.0
4
4
  * @license MIT
5
5
  *
@@ -15,12 +15,12 @@
15
15
 
16
16
  import { readFileSync } from "node:fs";
17
17
  import {
18
- isDynamic,
18
+ DEFAULT_LIT_HTML_SRC,
19
+ DEFAULT_REACTIVITY_SRC,
19
20
  compileStyles,
20
21
  escapeHtml,
22
+ isDynamic,
21
23
  tagNameToClassName,
22
- DEFAULT_REACTIVITY_SRC,
23
- DEFAULT_LIT_HTML_SRC,
24
24
  } from "./shared.ts";
25
25
  import { compileServer, compileSiteServer } from "./targets/compile-server.ts";
26
26
 
@@ -31,7 +31,10 @@ import {
31
31
  } from "./targets/compile-element.ts";
32
32
  import { compileStaticPage } from "./targets/compile-static.ts";
33
33
  import { compileClient } from "./targets/compile-client.ts";
34
- import type { JxMutableNode } from "@jxsuite/schema/types";
34
+ import { isClassDef } from "@jxsuite/schema/guards";
35
+ import { parseJxDocument } from "@jxsuite/schema/parse";
36
+ import type { JxDocument, JxStyle } from "@jxsuite/schema/types";
37
+ import type { FormatRegistry } from "@jxsuite/schema/format-registry";
35
38
 
36
39
  // Re-exports for consumers
37
40
  export {
@@ -45,77 +48,85 @@ export {
45
48
 
46
49
  // ─── Entry ────────────────────────────────────────────────────────────────────
47
50
 
51
+ export interface CompileOptions {
52
+ title?: string;
53
+ reactivitySrc?: string;
54
+ litHtmlSrc?: string;
55
+ projectStyle?: JxStyle | null;
56
+ formats?: FormatRegistry;
57
+ [key: string]: unknown;
58
+ }
59
+
48
60
  /**
49
61
  * Compile a Jx document to HTML (+ optional JS module files).
50
62
  *
51
63
  * Routing: 1. Not dynamic → static HTML/CSS, zero JS 2. tagName contains hyphen → custom element
52
64
  * (lit-html) 3. Otherwise → pre-rendered HTML with reactive bindings
53
65
  *
54
- * @param {string | any} sourcePath - Path to .json file, URL, or raw object
55
- * @param {Record<string, unknown>} [opts]
66
+ * @param {string | JxDocument} sourcePath - Path to .json file, URL, or raw document object
67
+ * @param {CompileOptions} [opts]
56
68
  * @returns {Promise<{
57
69
  * html: string;
58
70
  * files: { path: string; content: string; tagName?: string }[];
59
71
  * }>}
60
72
  */
61
- export async function compile(sourcePath: string | any, opts: Record<string, unknown> = {}) {
73
+ export async function compile(sourcePath: string | JxDocument, opts: CompileOptions = {}) {
62
74
  const {
63
75
  title = "Jx App",
64
76
  reactivitySrc = DEFAULT_REACTIVITY_SRC,
65
77
  litHtmlSrc = DEFAULT_LIT_HTML_SRC,
66
78
  projectStyle = null,
67
- } = opts as JxMutableNode;
79
+ } = opts;
68
80
 
69
- let raw;
81
+ let raw: JxDocument;
70
82
  if (typeof sourcePath === "string") {
71
83
  const source = readFileSync(sourcePath, "utf8");
72
84
  if (sourcePath.endsWith(".json")) {
73
- raw = JSON.parse(source);
85
+ raw = parseJxDocument(source, sourcePath);
74
86
  } else {
75
87
  const { extname } = await import("node:path");
76
88
  const ext = extname(sourcePath).toLowerCase();
77
- const registry = (opts as JxMutableNode)
78
- .formats as import("@jxsuite/schema/format-registry").FormatRegistry;
79
- const entry = registry?.byExtension?.(ext, "parse");
89
+ const entry = opts.formats?.byExtension?.(ext, "parse");
80
90
  if (!entry) {
81
91
  const { unknownFormatError } = await import("./site/format-host.ts");
82
92
  throw unknownFormatError(sourcePath, ext);
83
93
  }
84
- raw = await entry.call("parse", source);
94
+ // Format plugins contractually parse source text into a Jx document.
95
+ raw = (await entry.call("parse", source)) as JxDocument;
85
96
  }
86
97
  } else {
87
98
  raw = sourcePath;
88
99
  }
89
100
 
90
101
  // Route 0: .class.json schema-defined class → JS class module
91
- if (raw.$prototype === "Class") {
102
+ if (isClassDef(raw)) {
92
103
  const { compileClassJson } = await import("./targets/compile-class.js");
93
104
  const jsContent = compileClassJson(raw, opts);
94
105
  const outputPath =
95
106
  typeof sourcePath === "string"
96
107
  ? sourcePath.replace(/\.class\.json$/, ".js")
97
108
  : `${raw.title}.js`;
98
- return { html: "", files: [{ path: outputPath, content: jsContent }] };
109
+ return { files: [{ content: jsContent, path: outputPath }], html: "" };
99
110
  }
100
111
 
101
112
  // Route 1: Fully static → plain HTML/CSS
102
113
  if (!isDynamic(raw)) {
103
114
  return compileStaticPage(raw, {
104
- title,
105
- reactivitySrc,
106
115
  litHtmlSrc,
107
116
  projectStyle,
117
+ reactivitySrc,
118
+ title,
108
119
  });
109
120
  }
110
121
 
111
122
  // Route 2: Custom element tagName (contains hyphen) → lit-html web component
112
123
  if (raw.tagName && raw.tagName.includes("-")) {
113
- const tagName = raw.tagName;
124
+ const { tagName } = raw;
114
125
  const className = tagNameToClassName(tagName);
115
126
  const moduleContent = emitElementModule(raw, className, []);
116
127
  const moduleFile = {
117
- path: `${tagName}.js`,
118
128
  content: moduleContent,
129
+ path: `${tagName}.js`,
119
130
  tagName,
120
131
  };
121
132
  const styleBlock = compileStyles(raw, raw.$media ?? {});
@@ -142,11 +153,11 @@ export async function compile(sourcePath: string | any, opts: Record<string, unk
142
153
  </body>
143
154
  </html>`;
144
155
 
145
- return { html, files: [moduleFile] };
156
+ return { files: [moduleFile], html };
146
157
  }
147
158
 
148
159
  // Route 3: Dynamic with standard tagName → pre-rendered HTML + reactive bindings
149
- return compileClient(raw, { title, reactivitySrc, litHtmlSrc, projectStyle });
160
+ return compileClient(raw, { litHtmlSrc, projectStyle, reactivitySrc, title });
150
161
  }
151
162
 
152
163
  // ─── CLI ──────────────────────────────────────────────────────────────────────