@jxsuite/compiler 0.9.0 → 0.10.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jxsuite/compiler",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
4
4
  "description": "Jx static HTML compiler, island detector, and site builder",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -37,8 +37,8 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@apidevtools/json-schema-ref-parser": "^15.3.5",
40
- "@jxsuite/parser": "^0.7.0",
41
- "@jxsuite/runtime": "^0.7.0",
40
+ "@jxsuite/parser": "^0.10.0",
41
+ "@jxsuite/runtime": "^0.10.0",
42
42
  "remark-gfm": "^4.0.1",
43
43
  "remark-stringify": "^11.0.0",
44
44
  "sharp": "^0.34.5",
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from "./compiler.js";
3
+
4
+ const [, , src, out] = process.argv;
5
+ if (src) {
6
+ runCli(src, out).catch((err) => {
7
+ console.error(err);
8
+ process.exit(1);
9
+ });
10
+ }
package/src/compiler.js CHANGED
@@ -10,7 +10,7 @@
10
10
  * - Server → compile-server.js (Hono server handler)
11
11
  *
12
12
  * Usage (CLI):
13
- * bun packages/compiler/compiler.js <source.json> [output.html]
13
+ * bun packages/compiler/src/compile-cli.js <source.json> [output.html]
14
14
  */
15
15
 
16
16
  import { readFileSync } from "node:fs";
@@ -132,35 +132,30 @@ export async function compile(sourcePath, opts = {}) {
132
132
 
133
133
  // ─── CLI ──────────────────────────────────────────────────────────────────────
134
134
 
135
- const isMainModule = process.argv[1]?.endsWith("compiler.js");
136
- if (isMainModule && process.argv[2]) {
137
- const [, , src, out] = process.argv;
138
-
139
- Promise.all([compile(src), compileServer(src)])
140
- .then(async ([result, server]) => {
141
- const { writeFileSync, mkdirSync } = await import("node:fs");
142
- const { dirname, join } = await import("node:path");
143
- if (out) {
144
- writeFileSync(out, result.html, "utf8");
145
- console.error(`Written to ${out}`);
146
- const outDir = dirname(out);
147
- for (const f of result.files) {
148
- const filePath = join(outDir, f.path);
149
- mkdirSync(dirname(filePath), { recursive: true });
150
- writeFileSync(filePath, f.content, "utf8");
151
- console.error(`Written to ${filePath}`);
152
- }
153
- } else {
154
- process.stdout.write(result.html);
155
- }
156
- if (server && out) {
157
- const serverOut = out.replace(/(\.[^.]+)?$/, "-server.js");
158
- writeFileSync(serverOut, /** @type {string} */ (server), "utf8");
159
- console.error(`Server handler written to ${serverOut}`);
160
- }
161
- })
162
- .catch((/** @type {any} */ err) => {
163
- console.error(err);
164
- process.exit(1);
165
- });
135
+ /**
136
+ * @param {string} src
137
+ * @param {string} [out]
138
+ */
139
+ export async function runCli(src, out) {
140
+ const [result, server] = await Promise.all([compile(src), compileServer(src)]);
141
+ const { writeFileSync, mkdirSync } = await import("node:fs");
142
+ const { dirname, join } = await import("node:path");
143
+ if (out) {
144
+ writeFileSync(out, result.html, "utf8");
145
+ console.error(`Written to ${out}`);
146
+ const outDir = dirname(out);
147
+ for (const f of result.files) {
148
+ const filePath = join(outDir, f.path);
149
+ mkdirSync(dirname(filePath), { recursive: true });
150
+ writeFileSync(filePath, f.content, "utf8");
151
+ console.error(`Written to ${filePath}`);
152
+ }
153
+ } else {
154
+ process.stdout.write(result.html);
155
+ }
156
+ if (server && out) {
157
+ const serverOut = out.replace(/(\.[^.]+)?$/, "-server.js");
158
+ writeFileSync(serverOut, /** @type {string} */ (server), "utf8");
159
+ console.error(`Server handler written to ${serverOut}`);
160
+ }
166
161
  }
@@ -30,12 +30,13 @@ function parseCSV(csv) {
30
30
  /** @type {string[]} */
31
31
  const lines = [];
32
32
 
33
- // Split into rows respecting quoted newlines
33
+ // Split into rows respecting quoted newlines (preserve raw characters)
34
34
  for (let i = 0; i < csv.length; i++) {
35
35
  const ch = csv[i];
36
36
  if (ch === '"') {
37
+ current += ch;
37
38
  if (inQuotes && csv[i + 1] === '"') {
38
- current += '"';
39
+ current += csv[i + 1];
39
40
  i++;
40
41
  } else {
41
42
  inQuotes = !inQuotes;
@@ -155,7 +156,6 @@ function loadJSONEntries(filePath) {
155
156
  id: item.id ?? basename(filePath, ".json") + "-" + i,
156
157
  data: item,
157
158
  body: null,
158
- rendered: null,
159
159
  }));
160
160
  }
161
161
  // Single object file — filename is the id
@@ -164,7 +164,6 @@ function loadJSONEntries(filePath) {
164
164
  id: raw.id ?? basename(filePath, ".json"),
165
165
  data: raw,
166
166
  body: null,
167
- rendered: null,
168
167
  },
169
168
  ];
170
169
  }
@@ -192,7 +191,7 @@ function loadCSVEntries(filePath, schema) {
192
191
  }
193
192
  // Use `id` column, `sku` column, or row index as the entry ID
194
193
  const id = row.id ?? row.sku ?? String(i);
195
- return { id, data: row, body: null, rendered: null };
194
+ return { id, data: row, body: null };
196
195
  });
197
196
  }
198
197
 
@@ -173,7 +173,7 @@ export async function buildSite(projectRoot, options = {}) {
173
173
  // ── 5b. Collect server entries from components (for site-wide bundling) ──
174
174
  /** @type {{ exportName: string; src: string }[]} */
175
175
  const siteServerEntries = [];
176
- if (projectConfig.build.provider) {
176
+ if (projectConfig.build.adapter) {
177
177
  for (const [, doc] of componentDefs) {
178
178
  const entries = collectServerEntries(doc);
179
179
  for (const entry of entries) {
@@ -268,7 +268,7 @@ export async function buildSite(projectRoot, options = {}) {
268
268
  }
269
269
 
270
270
  // ── 6c. Generate site-wide server worker ────────────────────────────────
271
- if (projectConfig.build.provider && siteServerEntries.length > 0) {
271
+ if (projectConfig.build.adapter) {
272
272
  log("Generating site-wide server worker...");
273
273
 
274
274
  const deduped = new Map();
@@ -277,7 +277,7 @@ export async function buildSite(projectRoot, options = {}) {
277
277
  }
278
278
 
279
279
  const workerSource = compileSiteServer([...deduped.values()], {
280
- provider: projectConfig.build.provider,
280
+ adapter: projectConfig.build.adapter,
281
281
  });
282
282
 
283
283
  if (workerSource) {
@@ -459,7 +459,7 @@ async function compilePage(
459
459
  // Compile server handler if applicable (skip when provider bundles site-wide)
460
460
  /** @type {string | null} */
461
461
  let serverHandler = null;
462
- if (!projectConfig.build.provider) {
462
+ if (!projectConfig.build.adapter) {
463
463
  try {
464
464
  const serverResult = await compileServer(route.sourcePath);
465
465
  if (serverResult) {
@@ -342,12 +342,8 @@ function buildClientNode(def, raw, context, bindings, handlers, counter) {
342
342
  const value = resolveStaticValue(source.textContent, nextContext.scope);
343
343
  inner = value == null ? "" : escapeHtml(String(value));
344
344
  } else if (source.textContent !== undefined && needsBind) {
345
- try {
346
- const value = resolveStaticValue(source.textContent, nextContext.scope);
347
- inner = value == null ? "" : escapeHtml(String(value));
348
- } catch {
349
- inner = "";
350
- }
345
+ const value = resolveStaticValue(source.textContent, nextContext.scope);
346
+ inner = value == null ? "" : escapeHtml(String(value));
351
347
  } else if (source.innerHTML) {
352
348
  // resolveStaticValue may return null if innerHTML contains `${` from rendered content
353
349
  // (e.g., code examples) that isn't an actual template expression. Fall back to raw value.
@@ -607,29 +603,21 @@ function emitClientModule(
607
603
  if (onEntries.length > 0) {
608
604
  lines.push("const on = {");
609
605
  for (const [key, def] of onEntries) {
610
- if (def.imported) {
611
- const argNames = def.args ?? ["state"];
612
- const callArgs = argNames
613
- .map((/** @type {string} */ a) => (a === "state" ? "state" : "e"))
614
- .join(", ");
615
- lines.push(" " + key + ": (e) => { " + key + "(" + callArgs + "); },");
616
- } else {
617
- const argNames = def.args ?? ["state"];
618
- const callArgs = argNames
619
- .map((/** @type {string} */ a) => (a === "state" ? "state" : "e"))
620
- .join(", ");
621
- lines.push(
622
- " " +
623
- key +
624
- ": (e) => { const fn = (" +
625
- argNames.join(", ") +
626
- ") => { " +
627
- def.body +
628
- " }; fn(" +
629
- callArgs +
630
- "); },",
631
- );
632
- }
606
+ const argNames = def.args ?? ["state"];
607
+ const callArgs = argNames
608
+ .map((/** @type {string} */ a) => (a === "state" ? "state" : "e"))
609
+ .join(", ");
610
+ lines.push(
611
+ " " +
612
+ key +
613
+ ": (e) => { const fn = (" +
614
+ argNames.join(", ") +
615
+ ") => { " +
616
+ def.body +
617
+ " }; fn(" +
618
+ callArgs +
619
+ "); },",
620
+ );
633
621
  }
634
622
  lines.push("};");
635
623
  } else {
@@ -50,17 +50,17 @@ export default app
50
50
 
51
51
  /**
52
52
  * Generate a bundled Hono server entry from pre-collected server entries across an entire site.
53
- * Used when `build.provider` is set in project.json. Returns null if no entries are provided.
53
+ * Used when `build.adapter` is set in project.json. Returns null if no entries are provided.
54
54
  *
55
55
  * @param {{ exportName: string; src: string }[]} entries - Resolved server entries
56
56
  * @param {object} [opts]
57
57
  * @param {string} [opts.baseUrl] - Base path for server endpoints. Default is `'/_jx/server'`
58
- * @param {string | null} [opts.provider] - Deployment provider: `"cloudflare"`, `"node"`, `"bun"`
58
+ * @param {string | null} [opts.adapter] - Deployment adapter: `"cloudflare"`, `"node"`, `"bun"`
59
59
  * @returns {string | null} Complete worker/server source string, or null
60
60
  */
61
61
  export function compileSiteServer(entries, opts = {}) {
62
- const { baseUrl = "/_jx/server", provider = null } = opts;
63
- if (entries.length === 0) return null;
62
+ const { baseUrl = "/_jx/server", adapter = null } = opts;
63
+ if (entries.length === 0 && !adapter) return null;
64
64
 
65
65
  const imports = entries
66
66
  .map(({ exportName, src }) => `import { ${exportName} } from '${src}'`)
@@ -68,8 +68,8 @@ export function compileSiteServer(entries, opts = {}) {
68
68
 
69
69
  const routes = entries.map(({ exportName }) => buildRoute(exportName, baseUrl)).join("\n");
70
70
 
71
- const providerBlock =
72
- provider === "cloudflare" ? "\napp.all('*', (c) => c.env.ASSETS.fetch(c.req.raw))\n" : "\n";
71
+ const adapterBlock =
72
+ adapter === "cloudflare" ? "\napp.all('*', (c) => c.env.ASSETS.fetch(c.req.raw))\n" : "\n";
73
73
 
74
74
  return `// Generated by @jxsuite/compiler — do not edit manually
75
75
  import { Hono } from 'hono'
@@ -77,7 +77,7 @@ ${imports}
77
77
 
78
78
  const app = new Hono()
79
79
  ${routes}
80
- ${providerBlock}
80
+ ${adapterBlock}
81
81
  export default app
82
82
  `;
83
83
  }