@synopackageland/ui 0.6.0 → 0.6.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.
Files changed (2) hide show
  1. package/dist/cli.js +85 -78
  2. package/package.json +4 -1
package/dist/cli.js CHANGED
@@ -12,34 +12,41 @@ const K = [
12
12
  "/Applications/Chromium.app/Contents/MacOS/Chromium"
13
13
  ], X = ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"], z = ["ProgramFiles", "ProgramFiles(x86)", "LOCALAPPDATA"];
14
14
  function Q(e = process.env, t = process.platform, n = g) {
15
- return e.CHROME ? e.CHROME : (t === "darwin" ? K : t === "win32" ? z.flatMap((o) => e[o] ? [U.join(e[o], "Google", "Chrome", "Application", "chrome.exe")] : []) : (e.PATH ?? "").split(j.delimiter).filter(Boolean).flatMap((o) => X.map((r) => j.join(o, r)))).find(n);
15
+ return e.CHROME ? e.CHROME : (t === "darwin" ? K : t === "win32" ? z.flatMap((r) => e[r] ? [U.join(e[r], "Google", "Chrome", "Application", "chrome.exe")] : []) : (e.PATH ?? "").split(j.delimiter).filter(Boolean).flatMap((r) => X.map((o) => j.join(r, o)))).find(n);
16
16
  }
17
- async function Y(e) {
18
- const t = Q();
19
- if (!t) throw new Error("Chrome or Chromium was not found; set CHROME to its executable path.");
20
- const n = I(t, [
17
+ function Y(e, t = process.env) {
18
+ return [
21
19
  "--headless=new",
22
20
  "--disable-gpu",
23
21
  "--hide-scrollbars",
24
22
  "--no-first-run",
23
+ // Repaint whole tiles: partial raster redraws only the invalidated rect, and
24
+ // the anti-aliased edges it touches can come out one colour level apart, so
25
+ // the same page could otherwise screenshot differently from run to run.
26
+ "--disable-partial-raster",
25
27
  // GitHub's Ubuntu AppArmor policy blocks the unprivileged Chromium sandbox.
26
28
  // Match Playwright's CI launch defaults for these repository-only fixtures.
27
- ...process.env.CI ? ["--no-sandbox", "--disable-dev-shm-usage"] : [],
29
+ ...t.CI ? ["--no-sandbox", "--disable-dev-shm-usage"] : [],
28
30
  "--remote-debugging-port=0",
29
31
  `--user-data-dir=${e}`,
30
32
  "about:blank"
31
- ], { stdio: ["ignore", "ignore", "pipe"] });
32
- let s, o = "";
33
+ ];
34
+ }
35
+ async function Z(e) {
36
+ const t = Q();
37
+ if (!t) throw new Error("Chrome or Chromium was not found; set CHROME to its executable path.");
38
+ const n = I(t, Y(e), { stdio: ["ignore", "ignore", "pipe"] });
39
+ let s, r = "";
33
40
  n.once("error", (a) => {
34
41
  s = a;
35
42
  }), n.stderr.on("data", (a) => {
36
- o = (o + a).slice(-4e3);
43
+ r = (r + a).slice(-4e3);
37
44
  });
38
- const r = w(e, "DevToolsActivePort");
39
- for (let a = 0; a < 100 && !g(r) && !s && n.exitCode === null; a++) await L(100);
40
- if (!g(r))
41
- throw n.kill(), new Error(`Chrome failed to start: ${s?.message ?? (o || "no debugging port within 10 seconds")}`);
42
- const [i] = (await v(r, "utf8")).split(`
45
+ const o = w(e, "DevToolsActivePort");
46
+ for (let a = 0; a < 100 && !g(o) && !s && n.exitCode === null; a++) await L(100);
47
+ if (!g(o))
48
+ throw n.kill(), new Error(`Chrome failed to start: ${s?.message ?? (r || "no debugging port within 10 seconds")}`);
49
+ const [i] = (await v(o, "utf8")).split(`
43
50
  `), c = await (await fetch(`http://127.0.0.1:${i}/json/new?about:blank`, { method: "PUT" })).json(), d = new WebSocket(c.webSocketDebuggerUrl);
44
51
  await new Promise((a, m) => {
45
52
  d.onopen = a, d.onerror = m;
@@ -50,34 +57,34 @@ async function Y(e) {
50
57
  const m = JSON.parse(String(a.data));
51
58
  u.get(m.id)?.(m), u.delete(m.id);
52
59
  };
53
- const b = (a, m = {}) => new Promise((P, A) => {
60
+ const b = (a, m = {}) => new Promise((A, P) => {
54
61
  const O = l++;
55
- u.set(O, (h) => h.error ? A(new Error(h.error.message)) : P(h.result)), d.send(JSON.stringify({ id: O, method: a, params: m }));
62
+ u.set(O, (h) => h.error ? P(new Error(h.error.message)) : A(h.result)), d.send(JSON.stringify({ id: O, method: a, params: m }));
56
63
  });
57
64
  await b("Emulation.setDeviceMetricsOverride", { width: 1100, height: 720, deviceScaleFactor: 1, mobile: !1 });
58
65
  const k = new Promise((a) => n.once("exit", a));
59
66
  return { send: b, close: () => (d.close(), n.kill(), k) };
60
67
  }
61
- const Z = `<!doctype html>
68
+ const q = `<!doctype html>
62
69
  <html><head><meta charset="utf-8"><link rel="stylesheet" href="/theme.css">
63
70
  <style>html, body, #app { margin: 0; height: 100%; }</style></head>
64
71
  <body><div id="app"></div><script type="module" src="/preview.js"><\/script></body></html>`;
65
- function q(e, t) {
72
+ function ee(e, t) {
66
73
  const n = {
67
74
  "/theme.css": [new URL("theme.css", e), "text/css"],
68
75
  "/preview.js": [new URL("json-preview/preview.js", e), "text/javascript"]
69
- }, s = F(async (o, r) => {
70
- const i = new URL(o.url ?? "/", "http://localhost").pathname;
76
+ }, s = F(async (r, o) => {
77
+ const i = new URL(r.url ?? "/", "http://localhost").pathname;
71
78
  try {
72
- const [c, d] = i === "/" ? [Z, "text/html"] : i === "/config.json" ? [t, "application/json"] : [await v(n[i][0]), n[i][1]];
73
- r.writeHead(200, { "content-type": d }).end(c);
79
+ const [c, d] = i === "/" ? [q, "text/html"] : i === "/config.json" ? [t, "application/json"] : [await v(n[i][0]), n[i][1]];
80
+ o.writeHead(200, { "content-type": d }).end(c);
74
81
  } catch {
75
- r.writeHead(404).end();
82
+ o.writeHead(404).end();
76
83
  }
77
84
  });
78
- return new Promise((o) => s.listen(0, "127.0.0.1", () => o(s)));
85
+ return new Promise((r) => s.listen(0, "127.0.0.1", () => r(s)));
79
86
  }
80
- async function ee(e, t) {
87
+ async function te(e, t) {
81
88
  await e.send("Page.navigate", { url: t });
82
89
  const { result: n, exceptionDetails: s } = await e.send(
83
90
  "Runtime.evaluate",
@@ -96,21 +103,21 @@ async function ee(e, t) {
96
103
  if (s) throw new Error(`Rendering failed: ${s.exception?.description ?? "unknown error"}`);
97
104
  return n.value;
98
105
  }
99
- function te(e) {
106
+ function ne(e) {
100
107
  return async (t) => {
101
- const n = await q(e, JSON.stringify({ spec: t.spec, state: t.state, messages: t.messages })), s = `http://127.0.0.1:${n.address().port}/`, o = await E(w(H(), "syno-ui-render-"));
102
- let r;
108
+ const n = await ee(e, JSON.stringify({ spec: t.spec, state: t.state, messages: t.messages })), s = `http://127.0.0.1:${n.address().port}/`, r = await E(w(H(), "syno-ui-render-"));
109
+ let o;
103
110
  try {
104
- r = await Y(o), await M(t.out, { recursive: !0 });
111
+ o = await Z(r), await M(t.out, { recursive: !0 });
105
112
  const i = [];
106
113
  for (const c of t.widths) {
107
- await r.send("Emulation.setDeviceMetricsOverride", { width: c, height: t.height, deviceScaleFactor: 1, mobile: !1 });
108
- const d = await ee(r, `${s}?width=${c}`), { data: l } = await r.send("Page.captureScreenshot", { format: "png" }), u = w(t.out, `${t.name}-${c}.png`);
114
+ await o.send("Emulation.setDeviceMetricsOverride", { width: c, height: t.height, deviceScaleFactor: 1, mobile: !1 });
115
+ const d = await te(o, `${s}?width=${c}`), { data: l } = await o.send("Page.captureScreenshot", { format: "png" }), u = w(t.out, `${t.name}-${c}.png`);
109
116
  await D(u, Buffer.from(l, "base64")), i.push({ width: c, screenshot: u, issues: d });
110
117
  }
111
118
  return i;
112
119
  } finally {
113
- await r?.close(), n.close(), await R(o, { recursive: !0, force: !0, maxRetries: 12, retryDelay: 250 });
120
+ await o?.close(), n.close(), await R(r, { recursive: !0, force: !0, maxRetries: 12, retryDelay: 250 });
114
121
  }
115
122
  };
116
123
  }
@@ -133,17 +140,17 @@ Commands:
133
140
  --widths 390,640,960,1350 Viewport widths: phone, narrow window, DSM window, wide
134
141
  --height <px> Viewport height (default 800)
135
142
  --state, --messages As for validate; messages also back $computed t()
136
- `, ne = /* @__PURE__ */ new Set(["actions", "functions", "state", "messages", "out", "widths", "height", "wide"]);
137
- function se(e) {
143
+ `, se = /* @__PURE__ */ new Set(["actions", "functions", "state", "messages", "out", "widths", "height", "wide"]);
144
+ function re(e) {
138
145
  const t = [], n = {};
139
146
  for (let s = 0; s < e.length; s++) {
140
- const o = e[s];
141
- if (!o.startsWith("--")) {
142
- t.push(o);
147
+ const r = e[s];
148
+ if (!r.startsWith("--")) {
149
+ t.push(r);
143
150
  continue;
144
151
  }
145
- const [r, i] = o.slice(2).split("=", 2);
146
- n[r] = i ?? (ne.has(r) && e[s + 1] !== void 0 ? e[++s] : !0);
152
+ const [o, i] = r.slice(2).split("=", 2);
153
+ n[o] = i ?? (se.has(o) && e[s + 1] !== void 0 ? e[++s] : !0);
147
154
  }
148
155
  return { positional: t, flags: n };
149
156
  }
@@ -172,13 +179,13 @@ async function y(e, t) {
172
179
  }
173
180
  async function x(e, t, n) {
174
181
  const s = await C(e, t);
175
- let o;
182
+ let r;
176
183
  try {
177
- o = JSON.parse(s);
178
- } catch (r) {
179
- return { valid: !1, errors: [{ severity: "error", code: "invalid_json", path: "", message: r instanceof Error ? r.message : String(r), hint: "Return a single JSON object without comments or trailing commas." }], warnings: [] };
184
+ r = JSON.parse(s);
185
+ } catch (o) {
186
+ return { valid: !1, errors: [{ severity: "error", code: "invalid_json", path: "", message: o instanceof Error ? o.message : String(o), hint: "Return a single JSON object without comments or trailing commas." }], warnings: [] };
180
187
  }
181
- return G(o, n);
188
+ return G(r, n);
182
189
  }
183
190
  async function J(e, t) {
184
191
  return {
@@ -194,74 +201,74 @@ function $(e) {
194
201
  ${[...e.errors, ...e.warnings].map(oe).join("")}` : `${e.file}: OK
195
202
  `;
196
203
  }
197
- async function re(e, { positional: t, flags: n }) {
204
+ async function ie(e, { positional: t, flags: n }) {
198
205
  if (!t.length)
199
206
  return e.stderr(S), 2;
200
- const s = await J(e, n), o = [];
201
- for (const r of t) o.push({ file: r, ...await x(e, r, s) });
202
- return e.stdout(n.json ? JSON.stringify(o, null, 2) + `
203
- ` : o.map($).join("")), o.some((r) => N(r, n)) ? 1 : 0;
207
+ const s = await J(e, n), r = [];
208
+ for (const o of t) r.push({ file: o, ...await x(e, o, s) });
209
+ return e.stdout(n.json ? JSON.stringify(r, null, 2) + `
210
+ ` : r.map($).join("")), r.some((o) => N(o, n)) ? 1 : 0;
204
211
  }
205
- const ie = [390, 640, 960, 1350];
206
- async function ae(e, { positional: [t], flags: n }) {
212
+ const ae = [390, 640, 960, 1350];
213
+ async function ce(e, { positional: [t], flags: n }) {
207
214
  if (!t)
208
215
  return e.stderr(S), 2;
209
216
  if (!e.render)
210
217
  return e.stderr(`render needs a local Chrome or Chromium (set CHROME to its path) and Node 22 or newer.
211
218
  `), 2;
212
- const s = await J(e, n), o = { file: t, ...await x(e, t, s) };
213
- if (N(o, n))
214
- return e.stdout(n.json ? JSON.stringify({ file: t, validation: o, renders: [] }, null, 2) + `
215
- ` : $(o)), 1;
216
- const r = await e.render({
219
+ const s = await J(e, n), r = { file: t, ...await x(e, t, s) };
220
+ if (N(r, n))
221
+ return e.stdout(n.json ? JSON.stringify({ file: t, validation: r, renders: [] }, null, 2) + `
222
+ ` : $(r)), 1;
223
+ const o = await e.render({
217
224
  spec: await y(e, t),
218
225
  state: s.state,
219
226
  messages: s.messages,
220
- widths: f(n.widths)?.map(Number) ?? ie,
227
+ widths: f(n.widths)?.map(Number) ?? ae,
221
228
  height: typeof n.height == "string" ? Number(n.height) : 800,
222
229
  out: typeof n.out == "string" ? n.out : "syno-ui-render",
223
230
  name: t.split(/[\\/]/).pop().replace(/\.json$/i, "")
224
231
  }).catch((i) => {
225
232
  throw new p(`render failed: ${i instanceof Error ? i.message : String(i)}`);
226
233
  });
227
- if (n.json) e.stdout(JSON.stringify({ file: t, validation: o, renders: r }, null, 2) + `
234
+ if (n.json) e.stdout(JSON.stringify({ file: t, validation: r, renders: o }, null, 2) + `
228
235
  `);
229
236
  else {
230
- e.stdout(o.warnings.length ? $(o) : "");
231
- for (const { width: i, screenshot: c, issues: d } of r)
237
+ e.stdout(r.warnings.length ? $(r) : "");
238
+ for (const { width: i, screenshot: c, issues: d } of o)
232
239
  e.stdout(`${t} @${i}px: ${d.length ? `${d.length} layout issue(s)` : "OK"} ${c}
233
240
  ` + d.map((l) => ` ${l.kind} ${l.key ?? "(outside the spec)"}: ${l.detail}
234
241
  `).join(""));
235
242
  }
236
- return r.some((i) => i.issues.length) ? 1 : 0;
243
+ return o.some((i) => i.issues.length) ? 1 : 0;
237
244
  }
238
- async function ce(e, t) {
245
+ async function de(e, t) {
239
246
  try {
240
- return await de(se(e), t);
247
+ return await le(re(e), t);
241
248
  } catch (n) {
242
249
  if (!(n instanceof p)) throw n;
243
250
  return t.stderr(`${n.message}
244
251
  `), 2;
245
252
  }
246
253
  }
247
- async function de(e, t) {
248
- const [n, ...s] = e.positional, o = e.flags.json === !0;
254
+ async function le(e, t) {
255
+ const [n, ...s] = e.positional, r = e.flags.json === !0;
249
256
  switch (n) {
250
257
  case "catalog": {
251
- const r = B();
252
- return t.stdout(o ? JSON.stringify({ components: r }, null, 2) + `
253
- ` : r.map((i) => `${i.name}${i.required.length ? ` (${i.required.join(", ")})` : ""}: ${i.description}
258
+ const o = B();
259
+ return t.stdout(r ? JSON.stringify({ components: o }, null, 2) + `
260
+ ` : o.map((i) => `${i.name}${i.required.length ? ` (${i.required.join(", ")})` : ""}: ${i.description}
254
261
  `).join("")), 0;
255
262
  }
256
263
  case "describe": {
257
- const r = s[0] ?? "", i = _(r);
264
+ const o = s[0] ?? "", i = _(o);
258
265
  if (!i) {
259
- const c = V(r);
260
- return t.stderr(`Unknown component ${JSON.stringify(r)}.${c ? ` Did you mean "${c}"?` : ""} Run "syno-ui catalog".
266
+ const c = V(o);
267
+ return t.stderr(`Unknown component ${JSON.stringify(o)}.${c ? ` Did you mean "${c}"?` : ""} Run "syno-ui catalog".
261
268
  `), 2;
262
269
  }
263
- return t.stdout(o ? JSON.stringify(i, null, 2) + `
264
- ` : le(i)), 0;
270
+ return t.stdout(r ? JSON.stringify(i, null, 2) + `
271
+ ` : me(i)), 0;
265
272
  }
266
273
  case "schema":
267
274
  return t.stdout(JSON.stringify(W(), null, 2) + `
@@ -269,14 +276,14 @@ async function de(e, t) {
269
276
  case "prompt":
270
277
  return t.stdout(T()), 0;
271
278
  case "validate":
272
- return re(t, { positional: s, flags: e.flags });
279
+ return ie(t, { positional: s, flags: e.flags });
273
280
  case "render":
274
- return ae(t, { positional: s, flags: e.flags });
281
+ return ce(t, { positional: s, flags: e.flags });
275
282
  default:
276
283
  return t.stderr(S), 2;
277
284
  }
278
285
  }
279
- function le(e) {
286
+ function me(e) {
280
287
  const t = Object.entries(e.props).map(([n, s]) => ` ${n}${s.required ? "" : "?"}: ${JSON.stringify(s.schema)}
281
288
  `).join("");
282
289
  return `${e.name}: ${e.description}
@@ -287,10 +294,10 @@ events: ${e.events.join(", ") || "(none)"}
287
294
  example: ${JSON.stringify(e.example)}
288
295
  `;
289
296
  }
290
- process.exitCode = await ce(process.argv.slice(2), {
297
+ process.exitCode = await de(process.argv.slice(2), {
291
298
  stdout: (e) => process.stdout.write(e),
292
299
  stderr: (e) => process.stderr.write(e),
293
300
  readFile: (e) => v(e, "utf8"),
294
301
  // The DevTools connection uses the WebSocket global of Node 22 and newer.
295
- render: typeof WebSocket == "function" ? te(import.meta.url) : void 0
302
+ render: typeof WebSocket == "function" ? ne(import.meta.url) : void 0
296
303
  });
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.6.0",
2
+ "version": "0.6.1",
3
3
  "description": "Shared Vue 3 UI component library with a DSM 7 inspired application theme",
4
4
  "license": "MIT",
5
5
  "type": "module",
@@ -16,6 +16,9 @@
16
16
  "docs/component-defaults-0.5.7.md",
17
17
  "docs/json-ui.md"
18
18
  ],
19
+ "bin": {
20
+ "syno-ui": "./dist/cli.js"
21
+ },
19
22
  "main": "./dist/index.js",
20
23
  "module": "./dist/index.js",
21
24
  "types": "./dist/index.d.ts",