@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.
- package/dist/cli.js +85 -78
- 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((
|
|
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
|
-
|
|
18
|
-
|
|
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
|
-
...
|
|
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
|
-
]
|
|
32
|
-
|
|
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
|
-
|
|
43
|
+
r = (r + a).slice(-4e3);
|
|
37
44
|
});
|
|
38
|
-
const
|
|
39
|
-
for (let a = 0; a < 100 && !g(
|
|
40
|
-
if (!g(
|
|
41
|
-
throw n.kill(), new Error(`Chrome failed to start: ${s?.message ?? (
|
|
42
|
-
const [i] = (await v(
|
|
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((
|
|
60
|
+
const b = (a, m = {}) => new Promise((A, P) => {
|
|
54
61
|
const O = l++;
|
|
55
|
-
u.set(O, (h) => h.error ?
|
|
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
|
|
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
|
|
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 (
|
|
70
|
-
const i = new URL(
|
|
76
|
+
}, s = F(async (r, o) => {
|
|
77
|
+
const i = new URL(r.url ?? "/", "http://localhost").pathname;
|
|
71
78
|
try {
|
|
72
|
-
const [c, d] = i === "/" ? [
|
|
73
|
-
|
|
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
|
-
|
|
82
|
+
o.writeHead(404).end();
|
|
76
83
|
}
|
|
77
84
|
});
|
|
78
|
-
return new Promise((
|
|
85
|
+
return new Promise((r) => s.listen(0, "127.0.0.1", () => r(s)));
|
|
79
86
|
}
|
|
80
|
-
async function
|
|
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
|
|
106
|
+
function ne(e) {
|
|
100
107
|
return async (t) => {
|
|
101
|
-
const n = await
|
|
102
|
-
let
|
|
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
|
-
|
|
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
|
|
108
|
-
const d = await
|
|
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
|
|
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
|
-
`,
|
|
137
|
-
function
|
|
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
|
|
141
|
-
if (!
|
|
142
|
-
t.push(
|
|
147
|
+
const r = e[s];
|
|
148
|
+
if (!r.startsWith("--")) {
|
|
149
|
+
t.push(r);
|
|
143
150
|
continue;
|
|
144
151
|
}
|
|
145
|
-
const [
|
|
146
|
-
n[
|
|
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
|
|
182
|
+
let r;
|
|
176
183
|
try {
|
|
177
|
-
|
|
178
|
-
} catch (
|
|
179
|
-
return { valid: !1, errors: [{ severity: "error", code: "invalid_json", path: "", message:
|
|
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(
|
|
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
|
|
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),
|
|
201
|
-
for (const
|
|
202
|
-
return e.stdout(n.json ? JSON.stringify(
|
|
203
|
-
` :
|
|
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
|
|
206
|
-
async function
|
|
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),
|
|
213
|
-
if (N(
|
|
214
|
-
return e.stdout(n.json ? JSON.stringify({ file: t, validation:
|
|
215
|
-
` : $(
|
|
216
|
-
const
|
|
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) ??
|
|
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:
|
|
234
|
+
if (n.json) e.stdout(JSON.stringify({ file: t, validation: r, renders: o }, null, 2) + `
|
|
228
235
|
`);
|
|
229
236
|
else {
|
|
230
|
-
e.stdout(
|
|
231
|
-
for (const { width: i, screenshot: c, issues: d } of
|
|
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
|
|
243
|
+
return o.some((i) => i.issues.length) ? 1 : 0;
|
|
237
244
|
}
|
|
238
|
-
async function
|
|
245
|
+
async function de(e, t) {
|
|
239
246
|
try {
|
|
240
|
-
return await
|
|
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
|
|
248
|
-
const [n, ...s] = e.positional,
|
|
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
|
|
252
|
-
return t.stdout(
|
|
253
|
-
` :
|
|
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
|
|
264
|
+
const o = s[0] ?? "", i = _(o);
|
|
258
265
|
if (!i) {
|
|
259
|
-
const c = V(
|
|
260
|
-
return t.stderr(`Unknown component ${JSON.stringify(
|
|
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(
|
|
264
|
-
` :
|
|
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
|
|
279
|
+
return ie(t, { positional: s, flags: e.flags });
|
|
273
280
|
case "render":
|
|
274
|
-
return
|
|
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
|
|
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
|
|
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" ?
|
|
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.
|
|
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",
|