@jxsuite/compiler 0.28.0 → 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.0",
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.0",
46
- "@jxsuite/runtime": "^0.28.0",
47
- "@jxsuite/schema": "^0.28.0",
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,18 +15,14 @@
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
- import {
26
- compileServer,
27
- compileSiteServer,
28
- compilePagesFunctions,
29
- } from "./targets/compile-server.ts";
25
+ import { compileServer, compileSiteServer } from "./targets/compile-server.ts";
30
26
 
31
27
  import {
32
28
  compileElement,
@@ -35,14 +31,16 @@ import {
35
31
  } from "./targets/compile-element.ts";
36
32
  import { compileStaticPage } from "./targets/compile-static.ts";
37
33
  import { compileClient } from "./targets/compile-client.ts";
38
- 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";
39
38
 
40
39
  // Re-exports for consumers
41
40
  export {
42
41
  isDynamic,
43
42
  compileServer,
44
43
  compileSiteServer,
45
- compilePagesFunctions,
46
44
  compileElement,
47
45
  compileElementPage,
48
46
  compileClient,
@@ -50,77 +48,85 @@ export {
50
48
 
51
49
  // ─── Entry ────────────────────────────────────────────────────────────────────
52
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
+
53
60
  /**
54
61
  * Compile a Jx document to HTML (+ optional JS module files).
55
62
  *
56
63
  * Routing: 1. Not dynamic → static HTML/CSS, zero JS 2. tagName contains hyphen → custom element
57
64
  * (lit-html) 3. Otherwise → pre-rendered HTML with reactive bindings
58
65
  *
59
- * @param {string | any} sourcePath - Path to .json file, URL, or raw object
60
- * @param {Record<string, unknown>} [opts]
66
+ * @param {string | JxDocument} sourcePath - Path to .json file, URL, or raw document object
67
+ * @param {CompileOptions} [opts]
61
68
  * @returns {Promise<{
62
69
  * html: string;
63
70
  * files: { path: string; content: string; tagName?: string }[];
64
71
  * }>}
65
72
  */
66
- export async function compile(sourcePath: string | any, opts: Record<string, unknown> = {}) {
73
+ export async function compile(sourcePath: string | JxDocument, opts: CompileOptions = {}) {
67
74
  const {
68
75
  title = "Jx App",
69
76
  reactivitySrc = DEFAULT_REACTIVITY_SRC,
70
77
  litHtmlSrc = DEFAULT_LIT_HTML_SRC,
71
78
  projectStyle = null,
72
- } = opts as JxMutableNode;
79
+ } = opts;
73
80
 
74
- let raw;
81
+ let raw: JxDocument;
75
82
  if (typeof sourcePath === "string") {
76
83
  const source = readFileSync(sourcePath, "utf8");
77
84
  if (sourcePath.endsWith(".json")) {
78
- raw = JSON.parse(source);
85
+ raw = parseJxDocument(source, sourcePath);
79
86
  } else {
80
87
  const { extname } = await import("node:path");
81
88
  const ext = extname(sourcePath).toLowerCase();
82
- const registry = (opts as JxMutableNode)
83
- .formats as import("@jxsuite/schema/format-registry").FormatRegistry;
84
- const entry = registry?.byExtension?.(ext, "parse");
89
+ const entry = opts.formats?.byExtension?.(ext, "parse");
85
90
  if (!entry) {
86
91
  const { unknownFormatError } = await import("./site/format-host.ts");
87
92
  throw unknownFormatError(sourcePath, ext);
88
93
  }
89
- 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;
90
96
  }
91
97
  } else {
92
98
  raw = sourcePath;
93
99
  }
94
100
 
95
101
  // Route 0: .class.json schema-defined class → JS class module
96
- if (raw.$prototype === "Class") {
102
+ if (isClassDef(raw)) {
97
103
  const { compileClassJson } = await import("./targets/compile-class.js");
98
104
  const jsContent = compileClassJson(raw, opts);
99
105
  const outputPath =
100
106
  typeof sourcePath === "string"
101
107
  ? sourcePath.replace(/\.class\.json$/, ".js")
102
108
  : `${raw.title}.js`;
103
- return { html: "", files: [{ path: outputPath, content: jsContent }] };
109
+ return { files: [{ content: jsContent, path: outputPath }], html: "" };
104
110
  }
105
111
 
106
112
  // Route 1: Fully static → plain HTML/CSS
107
113
  if (!isDynamic(raw)) {
108
114
  return compileStaticPage(raw, {
109
- title,
110
- reactivitySrc,
111
115
  litHtmlSrc,
112
116
  projectStyle,
117
+ reactivitySrc,
118
+ title,
113
119
  });
114
120
  }
115
121
 
116
122
  // Route 2: Custom element tagName (contains hyphen) → lit-html web component
117
123
  if (raw.tagName && raw.tagName.includes("-")) {
118
- const tagName = raw.tagName;
124
+ const { tagName } = raw;
119
125
  const className = tagNameToClassName(tagName);
120
126
  const moduleContent = emitElementModule(raw, className, []);
121
127
  const moduleFile = {
122
- path: `${tagName}.js`,
123
128
  content: moduleContent,
129
+ path: `${tagName}.js`,
124
130
  tagName,
125
131
  };
126
132
  const styleBlock = compileStyles(raw, raw.$media ?? {});
@@ -147,11 +153,11 @@ export async function compile(sourcePath: string | any, opts: Record<string, unk
147
153
  </body>
148
154
  </html>`;
149
155
 
150
- return { html, files: [moduleFile] };
156
+ return { files: [moduleFile], html };
151
157
  }
152
158
 
153
159
  // Route 3: Dynamic with standard tagName → pre-rendered HTML + reactive bindings
154
- return compileClient(raw, { title, reactivitySrc, litHtmlSrc, projectStyle });
160
+ return compileClient(raw, { litHtmlSrc, projectStyle, reactivitySrc, title });
155
161
  }
156
162
 
157
163
  // ─── CLI ──────────────────────────────────────────────────────────────────────