@jxsuite/compiler 0.0.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.
@@ -0,0 +1,148 @@
1
+ /**
2
+ * jx-compiler.js — Compiler orchestrator
3
+ * @version 3.0.0
4
+ * @license MIT
5
+ *
6
+ * Routes Jx documents to the appropriate compilation target:
7
+ * - Fully static → compile-static.js (plain HTML/CSS, zero JS)
8
+ * - Custom element (-) → compile-element.js (lit-html web component)
9
+ * - Dynamic (standard) → compile-client.js (pre-rendered HTML + reactive bindings)
10
+ * - Server → compile-server.js (Hono server handler)
11
+ *
12
+ * Usage (CLI):
13
+ * bun packages/compiler/compiler.js <source.json> [output.html]
14
+ */
15
+
16
+ import { readFileSync } from "node:fs";
17
+ import {
18
+ isDynamic,
19
+ compileStyles,
20
+ escapeHtml,
21
+ tagNameToClassName,
22
+ DEFAULT_REACTIVITY_SRC,
23
+ DEFAULT_LIT_HTML_SRC,
24
+ } from "./shared.js";
25
+ import { compileServer } from "./targets/compile-server.js";
26
+ import {
27
+ compileElement,
28
+ compileElementPage,
29
+ emitElementModule,
30
+ } from "./targets/compile-element.js";
31
+ import { compileStaticPage } from "./targets/compile-static.js";
32
+ import { compileClient } from "./targets/compile-client.js";
33
+
34
+ // Re-exports for consumers
35
+ export { isDynamic, compileServer, compileElement, compileElementPage, compileClient };
36
+
37
+ // ─── Entry ────────────────────────────────────────────────────────────────────
38
+
39
+ /**
40
+ * Compile a Jx document to HTML (+ optional JS module files).
41
+ *
42
+ * Routing: 1. Not dynamic → static HTML/CSS, zero JS 2. tagName contains hyphen → custom element
43
+ * (lit-html) 3. Otherwise → pre-rendered HTML with reactive bindings
44
+ *
45
+ * @param {string | any} sourcePath - Path to .json file, URL, or raw object
46
+ * @param {any} [opts]
47
+ * @returns {Promise<{
48
+ * html: string;
49
+ * files: { path: string; content: string; tagName?: string }[];
50
+ * }>}
51
+ */
52
+ export async function compile(sourcePath, opts = {}) {
53
+ const {
54
+ title = "Jx App",
55
+ reactivitySrc = DEFAULT_REACTIVITY_SRC,
56
+ litHtmlSrc = DEFAULT_LIT_HTML_SRC,
57
+ } = opts;
58
+
59
+ const raw =
60
+ typeof sourcePath === "string" ? JSON.parse(readFileSync(sourcePath, "utf8")) : sourcePath;
61
+
62
+ // Route 0: .class.json schema-defined class → JS class module
63
+ if (raw.$prototype === "Class") {
64
+ const { compileClassJson } = await import("./targets/compile-class.js");
65
+ const jsContent = compileClassJson(raw, opts);
66
+ const outputPath =
67
+ typeof sourcePath === "string"
68
+ ? sourcePath.replace(/\.class\.json$/, ".js")
69
+ : `${raw.title}.js`;
70
+ return { html: "", files: [{ path: outputPath, content: jsContent }] };
71
+ }
72
+
73
+ // Route 1: Fully static → plain HTML/CSS
74
+ if (!isDynamic(raw)) {
75
+ return compileStaticPage(raw, { title, reactivitySrc, litHtmlSrc });
76
+ }
77
+
78
+ // Route 2: Custom element tagName (contains hyphen) → lit-html web component
79
+ if (raw.tagName && raw.tagName.includes("-")) {
80
+ const tagName = raw.tagName;
81
+ const className = tagNameToClassName(tagName);
82
+ const moduleContent = emitElementModule(raw, className, []);
83
+ const moduleFile = { path: `${tagName}.js`, content: moduleContent, tagName };
84
+ const styleBlock = compileStyles(raw, raw.$media ?? {});
85
+
86
+ const html = `<!DOCTYPE html>
87
+ <html lang="en">
88
+ <head>
89
+ <meta charset="utf-8">
90
+ <meta name="viewport" content="width=device-width, initial-scale=1">
91
+ <title>${escapeHtml(title)}</title>
92
+ <script type="importmap">
93
+ {
94
+ "imports": {
95
+ "@vue/reactivity": "${reactivitySrc}",
96
+ "lit-html": "${litHtmlSrc}"
97
+ }
98
+ }
99
+ </script>
100
+ ${styleBlock}
101
+ </head>
102
+ <body>
103
+ <${tagName}></${tagName}>
104
+ <script type="module" src="./${tagName}.js"></script>
105
+ </body>
106
+ </html>`;
107
+
108
+ return { html, files: [moduleFile] };
109
+ }
110
+
111
+ // Route 3: Dynamic with standard tagName → pre-rendered HTML + reactive bindings
112
+ return compileClient(raw, { title, reactivitySrc, litHtmlSrc });
113
+ }
114
+
115
+ // ─── CLI ──────────────────────────────────────────────────────────────────────
116
+
117
+ const isMainModule = process.argv[1]?.endsWith("compiler.js");
118
+ if (isMainModule && process.argv[2]) {
119
+ const [, , src, out] = process.argv;
120
+
121
+ Promise.all([compile(src), compileServer(src)])
122
+ .then(async ([result, server]) => {
123
+ const { writeFileSync, mkdirSync } = await import("node:fs");
124
+ const { dirname, join } = await import("node:path");
125
+ if (out) {
126
+ writeFileSync(out, result.html, "utf8");
127
+ console.error(`Written to ${out}`);
128
+ const outDir = dirname(out);
129
+ for (const f of result.files) {
130
+ const filePath = join(outDir, f.path);
131
+ mkdirSync(dirname(filePath), { recursive: true });
132
+ writeFileSync(filePath, f.content, "utf8");
133
+ console.error(`Written to ${filePath}`);
134
+ }
135
+ } else {
136
+ process.stdout.write(result.html);
137
+ }
138
+ if (server && out) {
139
+ const serverOut = out.replace(/(\.[^.]+)?$/, "-server.js");
140
+ writeFileSync(serverOut, /** @type {string} */ (server), "utf8");
141
+ console.error(`Server handler written to ${serverOut}`);
142
+ }
143
+ })
144
+ .catch((/** @type {any} */ err) => {
145
+ console.error(err);
146
+ process.exit(1);
147
+ });
148
+ }