@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.
- package/dist/compiler.js +165 -0
- package/package.json +38 -0
- package/src/cli.js +59 -0
- package/src/compiler.js +148 -0
- package/src/shared.js +690 -0
- package/src/site/content-loader.js +452 -0
- package/src/site/context-injection.js +152 -0
- package/src/site/head-merger.js +161 -0
- package/src/site/layout-resolver.js +182 -0
- package/src/site/pages-discovery.js +272 -0
- package/src/site/prototype-resolver.js +161 -0
- package/src/site/site-build.js +600 -0
- package/src/site/site-loader.js +85 -0
- package/src/targets/compile-class.js +194 -0
- package/src/targets/compile-client.js +806 -0
- package/src/targets/compile-element.js +619 -0
- package/src/targets/compile-server.js +57 -0
- package/src/targets/compile-static.js +155 -0
package/src/compiler.js
ADDED
|
@@ -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
|
+
}
|