@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
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile-class.js — Compile .class.json schema-defined classes to JavaScript ES modules
|
|
3
|
+
*
|
|
4
|
+
* Generates proper ES modules with private fields, static members, accessors, etc. from a JSON
|
|
5
|
+
* Schema 2020-12 class definition.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Compile a .class.json schema to a JavaScript ES module string.
|
|
10
|
+
*
|
|
11
|
+
* @param {any} classDef - Parsed .class.json content (must have $prototype: "Class")
|
|
12
|
+
* @param {any} [_opts]
|
|
13
|
+
* @returns {string} JavaScript module source code
|
|
14
|
+
*/
|
|
15
|
+
export function compileClassJson(classDef, _opts = {}) {
|
|
16
|
+
const className = classDef.title;
|
|
17
|
+
if (!className) throw new Error("compileClassJson: missing title (class name)");
|
|
18
|
+
|
|
19
|
+
const baseClass = resolveBaseClass(classDef.extends);
|
|
20
|
+
const fields = classDef.$defs?.fields ?? {};
|
|
21
|
+
const ctor = classDef.$defs?.constructor;
|
|
22
|
+
const methods = classDef.$defs?.methods ?? {};
|
|
23
|
+
|
|
24
|
+
/** @type {string[]} */
|
|
25
|
+
const lines = [];
|
|
26
|
+
lines.push("// Generated by @jxsuite/compiler from .class.json — do not edit manually");
|
|
27
|
+
if (classDef.$id) lines.push(`// Source: ${classDef.$id}`);
|
|
28
|
+
lines.push("");
|
|
29
|
+
|
|
30
|
+
// Class declaration
|
|
31
|
+
const extendsClause = baseClass !== "Object" ? ` extends ${baseClass}` : "";
|
|
32
|
+
lines.push(`class ${className}${extendsClause} {`);
|
|
33
|
+
|
|
34
|
+
// Static fields
|
|
35
|
+
for (const [key, field] of Object.entries(fields)) {
|
|
36
|
+
const f = /** @type {any} */ (field);
|
|
37
|
+
if (f.scope !== "static") continue;
|
|
38
|
+
const name = f.identifier ?? key;
|
|
39
|
+
const prefix = f.access === "private" ? "#" : "";
|
|
40
|
+
const initVal =
|
|
41
|
+
f.initializer !== undefined
|
|
42
|
+
? JSON.stringify(f.initializer)
|
|
43
|
+
: f.default !== undefined
|
|
44
|
+
? JSON.stringify(f.default)
|
|
45
|
+
: "null";
|
|
46
|
+
lines.push(` static ${prefix}${name} = ${initVal};`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Instance field declarations (private)
|
|
50
|
+
for (const [key, field] of Object.entries(fields)) {
|
|
51
|
+
const f = /** @type {any} */ (field);
|
|
52
|
+
if (f.scope === "static") continue;
|
|
53
|
+
if (f.access !== "private") continue;
|
|
54
|
+
const name = f.identifier ?? key;
|
|
55
|
+
lines.push(` #${name};`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (Object.keys(fields).length > 0) lines.push("");
|
|
59
|
+
|
|
60
|
+
// Constructor
|
|
61
|
+
lines.push(" constructor(config = {}) {");
|
|
62
|
+
if (ctor?.superCall || baseClass !== "Object") {
|
|
63
|
+
const superArgs = ctor?.superCall?.arguments ? ctor.superCall.arguments.join(", ") : "";
|
|
64
|
+
lines.push(` super(${superArgs});`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Initialize instance fields from config or defaults
|
|
68
|
+
for (const [key, field] of Object.entries(fields)) {
|
|
69
|
+
const f = /** @type {any} */ (field);
|
|
70
|
+
if (f.scope === "static") continue;
|
|
71
|
+
const name = f.identifier ?? key;
|
|
72
|
+
const prefix = f.access === "private" ? "#" : "";
|
|
73
|
+
const initVal =
|
|
74
|
+
f.initializer !== undefined
|
|
75
|
+
? JSON.stringify(f.initializer)
|
|
76
|
+
: f.default !== undefined
|
|
77
|
+
? JSON.stringify(f.default)
|
|
78
|
+
: "null";
|
|
79
|
+
lines.push(
|
|
80
|
+
` this.${prefix}${name} = config.${name} !== undefined ? config.${name} : ${initVal};`,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Constructor body statements
|
|
85
|
+
if (ctor?.body) {
|
|
86
|
+
const bodyLines = Array.isArray(ctor.body) ? ctor.body : [ctor.body];
|
|
87
|
+
for (const line of bodyLines) {
|
|
88
|
+
lines.push(` ${line}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
lines.push(" }");
|
|
92
|
+
|
|
93
|
+
// Methods
|
|
94
|
+
for (const [key, method] of Object.entries(methods)) {
|
|
95
|
+
const m = /** @type {any} */ (method);
|
|
96
|
+
const name = m.identifier ?? key;
|
|
97
|
+
const isStatic = m.scope === "static";
|
|
98
|
+
const isPrivate = m.access === "private";
|
|
99
|
+
const prefix = isPrivate ? "#" : "";
|
|
100
|
+
const staticPrefix = isStatic ? "static " : "";
|
|
101
|
+
const asyncPrefix = m.returnType?.$ref?.includes("Promise") || isMethodAsync(m) ? "async " : "";
|
|
102
|
+
|
|
103
|
+
const params = resolveParams(m.parameters ?? []);
|
|
104
|
+
const bodyStr = resolveBody(m.body);
|
|
105
|
+
|
|
106
|
+
lines.push("");
|
|
107
|
+
|
|
108
|
+
if (m.role === "accessor") {
|
|
109
|
+
// Getter
|
|
110
|
+
if (m.getter) {
|
|
111
|
+
lines.push(` ${staticPrefix}get ${prefix}${name}() {`);
|
|
112
|
+
lines.push(` ${m.getter.body}`);
|
|
113
|
+
lines.push(" }");
|
|
114
|
+
}
|
|
115
|
+
// Setter
|
|
116
|
+
if (m.setter) {
|
|
117
|
+
const setterParams = resolveParams(m.setter.parameters ?? []);
|
|
118
|
+
lines.push(` ${staticPrefix}set ${prefix}${name}(${setterParams}) {`);
|
|
119
|
+
lines.push(` ${m.setter.body}`);
|
|
120
|
+
lines.push(" }");
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
lines.push(` ${staticPrefix}${asyncPrefix}${prefix}${name}(${params}) {`);
|
|
124
|
+
for (const line of bodyStr) {
|
|
125
|
+
lines.push(` ${line}`);
|
|
126
|
+
}
|
|
127
|
+
lines.push(" }");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
lines.push("}");
|
|
132
|
+
lines.push("");
|
|
133
|
+
lines.push(`export { ${className} };`);
|
|
134
|
+
lines.push(`export default ${className};`);
|
|
135
|
+
lines.push("");
|
|
136
|
+
|
|
137
|
+
return lines.join("\n");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Resolve the base class name from an extends value.
|
|
142
|
+
*
|
|
143
|
+
* @param {any} ext
|
|
144
|
+
* @returns {string}
|
|
145
|
+
*/
|
|
146
|
+
function resolveBaseClass(ext) {
|
|
147
|
+
if (!ext) return "Object";
|
|
148
|
+
if (typeof ext === "string") return ext;
|
|
149
|
+
// { $ref: "./Parent.class.json" } — extract title from filename as best guess
|
|
150
|
+
if (ext.$ref) {
|
|
151
|
+
const ref = ext.$ref;
|
|
152
|
+
const match = ref.match(/([A-Za-z0-9_]+)\.class\.json/);
|
|
153
|
+
return match ? match[1] : "Object";
|
|
154
|
+
}
|
|
155
|
+
return "Object";
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Resolve parameter names from $ref or inline definitions.
|
|
160
|
+
*
|
|
161
|
+
* @param {any[]} params
|
|
162
|
+
* @returns {string}
|
|
163
|
+
*/
|
|
164
|
+
function resolveParams(params) {
|
|
165
|
+
return params
|
|
166
|
+
.map((/** @type {any} */ p) => {
|
|
167
|
+
if (p.$ref) return p.$ref.split("/").pop();
|
|
168
|
+
return p.identifier ?? p.name ?? "arg";
|
|
169
|
+
})
|
|
170
|
+
.join(", ");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Resolve body from string or array of strings.
|
|
175
|
+
*
|
|
176
|
+
* @param {any} body
|
|
177
|
+
* @returns {string[]}
|
|
178
|
+
*/
|
|
179
|
+
function resolveBody(body) {
|
|
180
|
+
if (!body) return [""];
|
|
181
|
+
if (Array.isArray(body)) return body;
|
|
182
|
+
return [body];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Simple heuristic: does the method body contain await?
|
|
187
|
+
*
|
|
188
|
+
* @param {any} method
|
|
189
|
+
* @returns {boolean}
|
|
190
|
+
*/
|
|
191
|
+
function isMethodAsync(method) {
|
|
192
|
+
const body = Array.isArray(method.body) ? method.body.join("\n") : (method.body ?? "");
|
|
193
|
+
return body.includes("await ");
|
|
194
|
+
}
|