@takazudo/zdtp 0.4.4 → 0.4.5

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.
@@ -19,11 +19,16 @@
19
19
  * opportunistically upgrades to v3 only when at least one semantic mapping is
20
20
  * one of the new `SemanticValue` object variants — v3 is a strict superset of
21
21
  * v2's shape, so this upgrade never loses information and never happens for a
22
- * doc that v2 could already represent losslessly. `deserialize()` accepts v1,
23
- * v2, and v3, and normalises to an internal `TweakState` regardless of which
24
- * schema was in the payload. Hosts that export v1 docs (custom `schemaId`) get
25
- * a `schema-mismatch` error on import unless they have opted into the
26
- * dual-accept path (see below).
22
+ * doc that v2 could already represent losslessly. `deserialize()` accepts
23
+ * exactly the three canonical `$schema` values above (`SCHEMA_V1`, `SCHEMA_V2`,
24
+ * `SCHEMA_V3`) and normalises to an internal `TweakState` regardless of which
25
+ * one was in the payload. `PanelConfig.schemaId` is a UI-label-only value
26
+ * (see `getDesignTokenSchema` below) that this package's own modals do NOT
27
+ * consult — `import-modal.tsx` / `export-modal.tsx` name the canonical
28
+ * constants directly in their copy. It is never consulted by
29
+ * `serialize()`/`deserialize()` either; a host that sets a custom `schemaId`
30
+ * still gets a `schema-mismatch` error importing any doc whose `$schema`
31
+ * isn't one of the three canonical constants (#498).
27
32
  *
28
33
  * ## v2 format
29
34
  *
@@ -98,15 +103,18 @@ export declare const SCHEMA_V3 = "zudo-design-tokens/v3";
98
103
  /**
99
104
  * Read the design-token schema id at call time.
100
105
  *
101
- * Returns the host-configured schema id from `cfg.schemaId`. Used as the
102
- * `$schema` value in legacy v1 exports (for hosts that have not upgraded their
103
- * config to v2) and as the expected-schema label the Import modal surfaces. The
104
- * canonical v2 serialize path always emits `SCHEMA_V2`.
106
+ * Returns the host-configured schema id from `cfg.schemaId`. This is a
107
+ * UI-label-only value on `PanelConfig` — it is never read by `serialize()`
108
+ * (which always emits `SCHEMA_V2` or `SCHEMA_V3`) or by `deserialize()`
109
+ * (which always validates against `SCHEMA_V1`/`SCHEMA_V2`/`SCHEMA_V3`); see
110
+ * the header comment above and #498. Neither `import-modal.tsx` nor
111
+ * `export-modal.tsx` calls this function — their copy names the actual
112
+ * `SCHEMA_V1`/`V2`/`V3` constants directly instead. This helper remains for
113
+ * hosts that want to read their own configured `schemaId` label without
114
+ * reaching into `PanelConfig` directly.
105
115
  *
106
116
  * `cfg` defaults to the active (most-recently-configured) instance so the
107
- * single-default path stays byte-identical. The Import modal threads its OWN
108
- * mounted instance config (multi-instance, #361) so a non-default panel
109
- * validates against ITS schema id, not the default's.
117
+ * single-default path stays byte-identical.
110
118
  */
111
119
  export declare function getDesignTokenSchema(cfg?: PanelConfig): string;
112
120
  /** External JSON value for a base-color / semantic-color entry (v1). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takazudo/zdtp",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "description": "Dynamic design-token tweak panel — host-config-driven, framework-agnostic Preact UI.",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -1,353 +0,0 @@
1
- import { promises as g, readFileSync as C } from "node:fs";
2
- import { relative as R, isAbsolute as T, sep as V, resolve as J, dirname as j, join as x } from "node:path";
3
- import { randomBytes as A } from "node:crypto";
4
- import { r as W } from "./route-tokens-to-files-1DvmWBdj.js";
5
- const F = /* @__PURE__ */ new Map();
6
- async function E(e, r) {
7
- const n = (F.get(e) ?? Promise.resolve()).then(r, r), o = n.then(
8
- () => {
9
- },
10
- () => {
11
- }
12
- );
13
- F.set(e, o);
14
- try {
15
- return await n;
16
- } finally {
17
- F.get(e) === o && F.delete(e);
18
- }
19
- }
20
- function z(e) {
21
- return e.replace(/[\r\n\\;{}]/g, "");
22
- }
23
- const M = /^--[a-zA-Z0-9_-]+$/;
24
- function I(e) {
25
- return typeof e == "string" && M.test(e);
26
- }
27
- function q(e, r) {
28
- if (!r.endsWith(".css")) return !1;
29
- const t = R(e, r);
30
- return !(t === "" || t === "." || T(t) || t === ".." || t.startsWith(`..${V}`) || t.startsWith("../"));
31
- }
32
- function B(e) {
33
- const r = {};
34
- for (const [t, n] of Object.entries(e)) {
35
- if (!I(t))
36
- return { error: `Invalid cssVar name: ${JSON.stringify(t)}` };
37
- if (typeof n != "string")
38
- return { error: `Value for ${t} must be a string` };
39
- r[t] = z(n);
40
- }
41
- return { sanitized: r };
42
- }
43
- class $ extends Error {
44
- constructor(r = 'No top-level ":root { ... }" block found in source.') {
45
- super(r), this.name = "NoRootBlockError", Object.setPrototypeOf(this, $.prototype);
46
- }
47
- }
48
- function N(e) {
49
- const r = e.length;
50
- let t = 0, n = 0;
51
- for (; t < r; ) {
52
- const o = e[t];
53
- if (o === "/" && e[t + 1] === "*") {
54
- const s = e.indexOf("*/", t + 2);
55
- if (s === -1) return null;
56
- t = s + 2;
57
- continue;
58
- }
59
- if (o === '"' || o === "'") {
60
- const s = o;
61
- for (t++; t < r && e[t] !== s; )
62
- e[t] === "\\" && t + 1 < r && t++, t++;
63
- t++;
64
- continue;
65
- }
66
- if (o === "{") {
67
- n++, t++;
68
- continue;
69
- }
70
- if (o === "}") {
71
- n > 0 && n--, t++;
72
- continue;
73
- }
74
- if (n === 0 && o === ":" && e.startsWith(":root", t)) {
75
- const s = t + 5, a = e[s] ?? "";
76
- if (!_(a)) {
77
- const l = Z(e, s);
78
- if (l !== -1) {
79
- const k = l + 1, c = D(e, k);
80
- return c !== -1 ? { contentStart: k, contentEnd: c } : null;
81
- }
82
- }
83
- }
84
- t++;
85
- }
86
- return null;
87
- }
88
- function _(e) {
89
- return /[A-Za-z0-9_-]/.test(e);
90
- }
91
- function Z(e, r) {
92
- const t = e.length;
93
- let n = r;
94
- for (; n < t; ) {
95
- const o = e[n];
96
- if (o === " " || o === " " || o === `
97
- ` || o === "\r" || o === "\f") {
98
- n++;
99
- continue;
100
- }
101
- if (o === "/" && e[n + 1] === "*") {
102
- const s = e.indexOf("*/", n + 2);
103
- if (s === -1) return -1;
104
- n = s + 2;
105
- continue;
106
- }
107
- return o === "{" ? n : -1;
108
- }
109
- return -1;
110
- }
111
- function D(e, r) {
112
- const t = e.length;
113
- let n = r, o = 1;
114
- for (; n < t; ) {
115
- const s = e[n];
116
- if (s === "/" && e[n + 1] === "*") {
117
- const a = e.indexOf("*/", n + 2);
118
- if (a === -1) return -1;
119
- n = a + 2;
120
- continue;
121
- }
122
- if (s === '"' || s === "'") {
123
- const a = s;
124
- for (n++; n < t && e[n] !== a; )
125
- e[n] === "\\" && n + 1 < t && n++, n++;
126
- n++;
127
- continue;
128
- }
129
- if (s === "{") {
130
- o++, n++;
131
- continue;
132
- }
133
- if (s === "}") {
134
- if (o--, o === 0) return n;
135
- n++;
136
- continue;
137
- }
138
- n++;
139
- }
140
- return -1;
141
- }
142
- function H(e) {
143
- return e.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
144
- }
145
- function L(e) {
146
- return e.replace(/\/\*[\s\S]*?\*\//g, (r) => " ".repeat(r.length));
147
- }
148
- function U(e, r, t) {
149
- const n = r.startsWith("--") ? r.slice(2) : r, o = H(n), s = new RegExp("(?<![\\w-])(--" + o + ":)(\\s*)([\\s\\S]+?);"), a = L(e), l = s.exec(a);
150
- if (!l) return { content: e, status: "unknown" };
151
- const [k, c, f] = l, y = l.index, w = y + k.length, v = y + c.length + f.length, p = w - 1, O = e.slice(v, p).trim(), S = t.trim();
152
- return O === S ? { content: e, status: "unchanged" } : { content: e.slice(0, y) + c + f + t + ";" + e.slice(w), status: "changed" };
153
- }
154
- function G(e, r) {
155
- const t = Object.keys(r), n = N(e);
156
- if (!n)
157
- return {
158
- updated: e,
159
- changed: [],
160
- unchanged: [],
161
- unknown: [...t]
162
- };
163
- let o = e.slice(n.contentStart, n.contentEnd);
164
- const s = [], a = [], l = [];
165
- for (const c of t) {
166
- const f = U(o, c, r[c]);
167
- o = f.content, f.status === "changed" ? s.push(c) : f.status === "unchanged" ? a.push(c) : l.push(c);
168
- }
169
- return { updated: e.slice(0, n.contentStart) + o + e.slice(n.contentEnd), changed: s, unchanged: a, unknown: l };
170
- }
171
- function K(e, r) {
172
- if (!N(e))
173
- throw new $();
174
- return G(e, r);
175
- }
176
- function u(e, r = 200) {
177
- return new Response(JSON.stringify(e), {
178
- status: r,
179
- headers: { "Content-Type": "application/json" }
180
- });
181
- }
182
- async function Q(e, r, t) {
183
- const n = await g.readFile(e, "utf-8"), o = K(n, t);
184
- return {
185
- absPath: e,
186
- relPath: r,
187
- original: n,
188
- updated: o.updated,
189
- changed: o.changed,
190
- unchanged: o.unchanged,
191
- unknown: o.unknown
192
- };
193
- }
194
- async function X(e) {
195
- if (e.changed.length !== 0)
196
- return E(e.absPath, async () => {
197
- const r = j(e.absPath), t = x(r, `.tmp-${A(8).toString("hex")}.css`);
198
- try {
199
- await g.writeFile(t, e.updated, "utf-8"), await g.rename(t, e.absPath);
200
- } catch (n) {
201
- try {
202
- await g.unlink(t);
203
- } catch {
204
- }
205
- throw n;
206
- }
207
- });
208
- }
209
- async function Y(e) {
210
- return E(e.absPath, async () => {
211
- const r = j(e.absPath), t = x(r, `.tmp-${A(8).toString("hex")}.css`);
212
- try {
213
- return await g.writeFile(t, e.original, "utf-8"), await g.rename(t, e.absPath), { ok: !0 };
214
- } catch (n) {
215
- console.error("[design-token-panel/server] Restore failed for", e.relPath, n);
216
- try {
217
- await g.unlink(t);
218
- } catch {
219
- }
220
- return { ok: !1, error: n };
221
- }
222
- });
223
- }
224
- function se(e) {
225
- const { rootDir: r, writeRoot: t, routing: n } = e;
226
- return async function(s) {
227
- let a;
228
- try {
229
- a = await s.json();
230
- } catch {
231
- return u({ ok: !1, error: "Invalid JSON in request body" }, 400);
232
- }
233
- if (typeof a != "object" || a === null || Array.isArray(a))
234
- return u({ ok: !1, error: "Request body must be a JSON object" }, 400);
235
- const { tokens: l } = a;
236
- if (typeof l != "object" || l === null || Array.isArray(l))
237
- return u({ ok: !1, error: "tokens must be a JSON object" }, 400);
238
- if (Object.entries(l).length === 0)
239
- return u({ ok: !1, error: "tokens must contain at least one entry" }, 400);
240
- const { sanitized: c, error: f } = B(l);
241
- if (f || !c)
242
- return u({ ok: !1, error: f ?? "Invalid tokens" }, 400);
243
- const { groups: y, rejected: w } = W(c, n);
244
- if (w.length > 0)
245
- return u({ ok: !1, error: "Unsupported cssVar prefix", rejected: w }, 400);
246
- if (y.length === 0)
247
- return u({ ok: !1, error: "No routable tokens supplied" }, 400);
248
- const v = [];
249
- for (const i of y) {
250
- const d = J(r, i.relativePath);
251
- if (!q(t, d))
252
- return u({ ok: !1, error: `Path not allowed: ${i.relativePath}` }, 400);
253
- v.push({ absPath: d, relPath: i.relativePath, groupTokens: i.tokens });
254
- }
255
- const p = [];
256
- for (const { absPath: i, relPath: d, groupTokens: m } of v)
257
- try {
258
- p.push(await Q(i, d, m));
259
- } catch (h) {
260
- return h instanceof $ ? (console.error("[design-token-panel/server] No :root block in", d), u(
261
- {
262
- ok: !1,
263
- error: `No top-level :root { ... } block in ${d}`
264
- },
265
- 409
266
- )) : (console.error(`[design-token-panel/server] Error computing ${d}:`, h), u({ ok: !1, error: "Failed to read or parse source file" }, 500));
267
- }
268
- const b = [];
269
- for (const i of p)
270
- try {
271
- await X(i), b.push(i);
272
- } catch (d) {
273
- console.error(`[design-token-panel/server] Write failed for ${i.relPath}:`, d);
274
- const m = [];
275
- for (let h = b.length - 1; h >= 0; h--)
276
- (await Y(b[h])).ok || m.push(b[h].relPath);
277
- return m.length > 0 ? u(
278
- {
279
- ok: !1,
280
- error: `Failed to write file ${i.relPath}; rollback also failed for ${m.length} file(s) — disk state is inconsistent. Inspect the listed files manually.`,
281
- failedFile: i.relPath,
282
- restoreFailures: m
283
- },
284
- 500
285
- ) : u(
286
- {
287
- ok: !1,
288
- error: `Failed to write file ${i.relPath}; previously-written files were restored.`,
289
- failedFile: i.relPath
290
- },
291
- 500
292
- );
293
- }
294
- const O = p.flatMap((i) => i.unknown), S = p.flatMap((i) => i.unchanged), P = p.map((i) => ({
295
- file: i.relPath.startsWith("/") ? R(r, i.relPath) : i.relPath,
296
- changed: i.changed,
297
- unchanged: i.unchanged,
298
- unknown: i.unknown
299
- }));
300
- return u({
301
- ok: !0,
302
- updated: P,
303
- unknownCssVars: O,
304
- unchangedCssVars: S
305
- });
306
- };
307
- }
308
- function ie(e) {
309
- let r;
310
- try {
311
- r = C(e, "utf-8");
312
- } catch (s) {
313
- throw new Error(
314
- `[design-token-panel] loadRoutingFromFile: cannot read file at ${e}
315
- Cause: ${s.message}`
316
- );
317
- }
318
- let t;
319
- try {
320
- t = JSON.parse(r);
321
- } catch (s) {
322
- throw new Error(
323
- `[design-token-panel] loadRoutingFromFile: invalid JSON in ${e}
324
- Cause: ${s.message}`
325
- );
326
- }
327
- if (t === null || typeof t != "object" || Array.isArray(t))
328
- throw new Error(
329
- `[design-token-panel] loadRoutingFromFile: root value must be a plain object, got ${t === null ? "null" : Array.isArray(t) ? "array" : typeof t} (in ${e})`
330
- );
331
- const n = t, o = Object.keys(n);
332
- if (o.length === 0)
333
- throw new Error(
334
- `[design-token-panel] loadRoutingFromFile: routing map must not be empty (in ${e})`
335
- );
336
- for (const s of o) {
337
- const a = n[s];
338
- if (typeof a != "string" || a.trim() === "")
339
- throw new Error(
340
- `[design-token-panel] loadRoutingFromFile: every value must be a non-empty string, but key "${s}" has value ${JSON.stringify(a)} (in ${e})`
341
- );
342
- }
343
- return n;
344
- }
345
- export {
346
- M as C,
347
- I as a,
348
- se as c,
349
- q as i,
350
- ie as l,
351
- E as s,
352
- B as v
353
- };