@zeroxsolutions/zaku 0.0.2 → 0.0.4
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/rules.js +1 -1
- package/dist/zaku.mjs +1581 -262
- package/package.json +1 -1
package/dist/zaku.mjs
CHANGED
|
@@ -12066,7 +12066,7 @@ var require_websocket = __commonJS({
|
|
|
12066
12066
|
var http = __require("http");
|
|
12067
12067
|
var net = __require("net");
|
|
12068
12068
|
var tls = __require("tls");
|
|
12069
|
-
var { randomBytes, createHash:
|
|
12069
|
+
var { randomBytes, createHash: createHash3 } = __require("crypto");
|
|
12070
12070
|
var { Duplex, Readable } = __require("stream");
|
|
12071
12071
|
var { URL: URL2 } = __require("url");
|
|
12072
12072
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -12747,7 +12747,7 @@ var require_websocket = __commonJS({
|
|
|
12747
12747
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
12748
12748
|
return;
|
|
12749
12749
|
}
|
|
12750
|
-
const digest =
|
|
12750
|
+
const digest = createHash3("sha1").update(key + GUID).digest("base64");
|
|
12751
12751
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
12752
12752
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
12753
12753
|
return;
|
|
@@ -13116,7 +13116,7 @@ var require_websocket_server = __commonJS({
|
|
|
13116
13116
|
var EventEmitter2 = __require("events");
|
|
13117
13117
|
var http = __require("http");
|
|
13118
13118
|
var { Duplex } = __require("stream");
|
|
13119
|
-
var { createHash:
|
|
13119
|
+
var { createHash: createHash3 } = __require("crypto");
|
|
13120
13120
|
var extension2 = require_extension();
|
|
13121
13121
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
13122
13122
|
var subprotocol2 = require_subprotocol();
|
|
@@ -13423,7 +13423,7 @@ var require_websocket_server = __commonJS({
|
|
|
13423
13423
|
);
|
|
13424
13424
|
}
|
|
13425
13425
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
13426
|
-
const digest =
|
|
13426
|
+
const digest = createHash3("sha1").update(key + GUID).digest("base64");
|
|
13427
13427
|
const headers = [
|
|
13428
13428
|
"HTTP/1.1 101 Switching Protocols",
|
|
13429
13429
|
"Upgrade: websocket",
|
|
@@ -17351,49 +17351,49 @@ var require_fast_uri = __commonJS({
|
|
|
17351
17351
|
schemelessOptions.skipEscape = true;
|
|
17352
17352
|
return serialize(resolved, schemelessOptions);
|
|
17353
17353
|
}
|
|
17354
|
-
function resolveComponent(base,
|
|
17354
|
+
function resolveComponent(base, relative3, options, skipNormalization) {
|
|
17355
17355
|
const target = {};
|
|
17356
17356
|
if (!skipNormalization) {
|
|
17357
17357
|
base = parse4(serialize(base, options), options);
|
|
17358
|
-
|
|
17358
|
+
relative3 = parse4(serialize(relative3, options), options);
|
|
17359
17359
|
}
|
|
17360
17360
|
options = options || {};
|
|
17361
|
-
if (!options.tolerant &&
|
|
17362
|
-
target.scheme =
|
|
17363
|
-
target.userinfo =
|
|
17364
|
-
target.host =
|
|
17365
|
-
target.port =
|
|
17366
|
-
target.path = removeDotSegments(
|
|
17367
|
-
target.query =
|
|
17361
|
+
if (!options.tolerant && relative3.scheme) {
|
|
17362
|
+
target.scheme = relative3.scheme;
|
|
17363
|
+
target.userinfo = relative3.userinfo;
|
|
17364
|
+
target.host = relative3.host;
|
|
17365
|
+
target.port = relative3.port;
|
|
17366
|
+
target.path = removeDotSegments(relative3.path || "");
|
|
17367
|
+
target.query = relative3.query;
|
|
17368
17368
|
} else {
|
|
17369
|
-
if (
|
|
17370
|
-
target.userinfo =
|
|
17371
|
-
target.host =
|
|
17372
|
-
target.port =
|
|
17373
|
-
target.path = removeDotSegments(
|
|
17374
|
-
target.query =
|
|
17369
|
+
if (relative3.userinfo !== void 0 || relative3.host !== void 0 || relative3.port !== void 0) {
|
|
17370
|
+
target.userinfo = relative3.userinfo;
|
|
17371
|
+
target.host = relative3.host;
|
|
17372
|
+
target.port = relative3.port;
|
|
17373
|
+
target.path = removeDotSegments(relative3.path || "");
|
|
17374
|
+
target.query = relative3.query;
|
|
17375
17375
|
} else {
|
|
17376
|
-
if (!
|
|
17376
|
+
if (!relative3.path) {
|
|
17377
17377
|
target.path = base.path;
|
|
17378
|
-
if (
|
|
17379
|
-
target.query =
|
|
17378
|
+
if (relative3.query !== void 0) {
|
|
17379
|
+
target.query = relative3.query;
|
|
17380
17380
|
} else {
|
|
17381
17381
|
target.query = base.query;
|
|
17382
17382
|
}
|
|
17383
17383
|
} else {
|
|
17384
|
-
if (
|
|
17385
|
-
target.path = removeDotSegments(
|
|
17384
|
+
if (relative3.path[0] === "/") {
|
|
17385
|
+
target.path = removeDotSegments(relative3.path);
|
|
17386
17386
|
} else {
|
|
17387
17387
|
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
|
|
17388
|
-
target.path = "/" +
|
|
17388
|
+
target.path = "/" + relative3.path;
|
|
17389
17389
|
} else if (!base.path) {
|
|
17390
|
-
target.path =
|
|
17390
|
+
target.path = relative3.path;
|
|
17391
17391
|
} else {
|
|
17392
|
-
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
17392
|
+
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative3.path;
|
|
17393
17393
|
}
|
|
17394
17394
|
target.path = removeDotSegments(target.path);
|
|
17395
17395
|
}
|
|
17396
|
-
target.query =
|
|
17396
|
+
target.query = relative3.query;
|
|
17397
17397
|
}
|
|
17398
17398
|
target.userinfo = base.userinfo;
|
|
17399
17399
|
target.host = base.host;
|
|
@@ -17401,7 +17401,7 @@ var require_fast_uri = __commonJS({
|
|
|
17401
17401
|
}
|
|
17402
17402
|
target.scheme = base.scheme;
|
|
17403
17403
|
}
|
|
17404
|
-
target.fragment =
|
|
17404
|
+
target.fragment = relative3.fragment;
|
|
17405
17405
|
return target;
|
|
17406
17406
|
}
|
|
17407
17407
|
function equal(uriA, uriB, options) {
|
|
@@ -20678,10 +20678,10 @@ var require_dist2 = __commonJS({
|
|
|
20678
20678
|
|
|
20679
20679
|
// apps/zaku-cli/src/cli.ts
|
|
20680
20680
|
var import_reflect_metadata3 = __toESM(require_Reflect(), 1);
|
|
20681
|
-
import { readFile as
|
|
20681
|
+
import { readFile as readFile6 } from "node:fs/promises";
|
|
20682
20682
|
import { createRequire } from "node:module";
|
|
20683
20683
|
import { homedir as homedir2 } from "node:os";
|
|
20684
|
-
import { dirname as dirname4, join as
|
|
20684
|
+
import { dirname as dirname4, join as join12, resolve as resolve2, sep } from "node:path";
|
|
20685
20685
|
import { fileURLToPath } from "node:url";
|
|
20686
20686
|
|
|
20687
20687
|
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/error.js
|
|
@@ -21859,7 +21859,7 @@ var Command = class _Command extends EventEmitter {
|
|
|
21859
21859
|
this._outputConfiguration = {
|
|
21860
21860
|
writeOut: (str) => process2.stdout.write(str),
|
|
21861
21861
|
writeErr: (str) => process2.stderr.write(str),
|
|
21862
|
-
outputError: (str,
|
|
21862
|
+
outputError: (str, write2) => write2(str),
|
|
21863
21863
|
getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : void 0,
|
|
21864
21864
|
getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : void 0,
|
|
21865
21865
|
getOutHasColors: () => useColor() ?? (process2.stdout.isTTY && process2.stdout.hasColors?.()),
|
|
@@ -23844,11 +23844,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
23844
23844
|
hasColors = this._outputConfiguration.getOutHasColors();
|
|
23845
23845
|
helpWidth = this._outputConfiguration.getOutHelpWidth();
|
|
23846
23846
|
}
|
|
23847
|
-
const
|
|
23847
|
+
const write2 = (str) => {
|
|
23848
23848
|
if (!hasColors) str = this._outputConfiguration.stripColor(str);
|
|
23849
23849
|
return baseWrite(str);
|
|
23850
23850
|
};
|
|
23851
|
-
return { error: error62, write, hasColors, helpWidth };
|
|
23851
|
+
return { error: error62, write: write2, hasColors, helpWidth };
|
|
23852
23852
|
}
|
|
23853
23853
|
/**
|
|
23854
23854
|
* Output help information for this command.
|
|
@@ -24178,11 +24178,15 @@ var WriteRecipe = class extends DomainCommand {
|
|
|
24178
24178
|
// packages/zaku/dist/lib/commands/save-library.js
|
|
24179
24179
|
var SaveLibrary = class extends DomainCommand {
|
|
24180
24180
|
root;
|
|
24181
|
+
key;
|
|
24181
24182
|
part;
|
|
24182
24183
|
constructor(input2) {
|
|
24183
24184
|
super();
|
|
24184
24185
|
this.root = input2.root;
|
|
24185
|
-
|
|
24186
|
+
if (input2.key !== void 0)
|
|
24187
|
+
this.key = input2.key;
|
|
24188
|
+
if (input2.part !== void 0)
|
|
24189
|
+
this.part = input2.part;
|
|
24186
24190
|
}
|
|
24187
24191
|
};
|
|
24188
24192
|
|
|
@@ -24325,8 +24329,8 @@ function parseCssColour(value) {
|
|
|
24325
24329
|
return null;
|
|
24326
24330
|
return name === "oklch" ? oklchToRgba(l, x, y, round(alpha)) : oklabToRgba(l, x, y, round(alpha));
|
|
24327
24331
|
}
|
|
24328
|
-
function rgbaToOklab(
|
|
24329
|
-
const [r, g, b] = [decode(
|
|
24332
|
+
function rgbaToOklab(colour3) {
|
|
24333
|
+
const [r, g, b] = [decode(colour3.r), decode(colour3.g), decode(colour3.b)];
|
|
24330
24334
|
const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
|
|
24331
24335
|
const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
|
|
24332
24336
|
const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
|
|
@@ -24341,12 +24345,12 @@ function deltaEOk(a, b) {
|
|
|
24341
24345
|
const [l2, a2, b2] = rgbaToOklab(b);
|
|
24342
24346
|
return Math.round(Math.hypot(l1 - l2, a1 - a2, b1 - b2, a.a - b.a) * 100 * 1e3) / 1e3;
|
|
24343
24347
|
}
|
|
24344
|
-
function toHex(
|
|
24345
|
-
const channels = [
|
|
24348
|
+
function toHex(colour3) {
|
|
24349
|
+
const channels = [colour3.r, colour3.g, colour3.b].map((value) => Math.round(clamp(value) * 255).toString(16).padStart(2, "0"));
|
|
24346
24350
|
return `#${channels.join("")}`;
|
|
24347
24351
|
}
|
|
24348
|
-
function luminance(
|
|
24349
|
-
return 0.2126 * decode(
|
|
24352
|
+
function luminance(colour3) {
|
|
24353
|
+
return 0.2126 * decode(colour3.r) + 0.7152 * decode(colour3.g) + 0.0722 * decode(colour3.b);
|
|
24350
24354
|
}
|
|
24351
24355
|
function contrastRatio(fg, bg) {
|
|
24352
24356
|
const over = (front, back) => front * fg.a + back * (1 - fg.a);
|
|
@@ -44393,6 +44397,18 @@ var FigmaTokenMissing = class extends Error {
|
|
|
44393
44397
|
}
|
|
44394
44398
|
};
|
|
44395
44399
|
|
|
44400
|
+
// packages/zaku/dist/lib/domain/errors/library-key-missing.js
|
|
44401
|
+
var LibraryKeyMissing = class extends Error {
|
|
44402
|
+
keys;
|
|
44403
|
+
given;
|
|
44404
|
+
constructor(keys, given) {
|
|
44405
|
+
super(given === void 0 ? `zaku.yaml lists several libraries and kits; name one with --key: ${keys.join(", ")}` : `${given} is not a library or kit zaku.yaml lists; name one with --key: ${keys.join(", ")}`);
|
|
44406
|
+
this.keys = keys;
|
|
44407
|
+
this.given = given;
|
|
44408
|
+
this.name = "LibraryKeyMissing";
|
|
44409
|
+
}
|
|
44410
|
+
};
|
|
44411
|
+
|
|
44396
44412
|
// packages/zaku/dist/lib/domain/errors/playwright-missing.js
|
|
44397
44413
|
var PlaywrightMissing = class extends Error {
|
|
44398
44414
|
constructor() {
|
|
@@ -44518,18 +44534,18 @@ function radiiOf(raw) {
|
|
|
44518
44534
|
return fitRadii(corners, raw.width, raw.height);
|
|
44519
44535
|
}
|
|
44520
44536
|
function partOf(raw, at) {
|
|
44521
|
-
const
|
|
44537
|
+
const colour3 = (field, value) => {
|
|
44522
44538
|
const parsed = parseCssColour(value);
|
|
44523
44539
|
if (!parsed)
|
|
44524
44540
|
throw new Error(`${at}, part ${raw.part}: ${field} is ${value}, which zaku does not read`);
|
|
44525
44541
|
return parsed;
|
|
44526
44542
|
};
|
|
44527
|
-
const background =
|
|
44543
|
+
const background = colour3("background", raw.background);
|
|
44528
44544
|
const gap = Number.parseFloat(raw.gap);
|
|
44529
44545
|
return {
|
|
44530
44546
|
background: background.a === 0 ? null : background,
|
|
44531
|
-
color:
|
|
44532
|
-
borderColor: raw.borderWidths.some((width) => width > 0) ?
|
|
44547
|
+
color: colour3("color", raw.color),
|
|
44548
|
+
borderColor: raw.borderWidths.some((width) => width > 0) ? colour3("borderColor", raw.borderColor) : null,
|
|
44533
44549
|
borderWidths: raw.borderWidths,
|
|
44534
44550
|
width: raw.width,
|
|
44535
44551
|
height: raw.height,
|
|
@@ -44611,13 +44627,106 @@ WriteRecipeHandler = __decorate2([
|
|
|
44611
44627
|
|
|
44612
44628
|
// packages/zaku/dist/lib/handlers/save-library.js
|
|
44613
44629
|
var import_tsyringe3 = __toESM(require_cjs(), 1);
|
|
44614
|
-
import {
|
|
44630
|
+
import { relative as relative2 } from "node:path";
|
|
44615
44631
|
|
|
44616
44632
|
// packages/zaku/dist/lib/domain/copy-defaults.js
|
|
44617
44633
|
var DEFAULT_COPY = { locales: ["en"], currencies: [] };
|
|
44618
44634
|
|
|
44635
|
+
// packages/zaku/dist/lib/domain/design-graph.js
|
|
44636
|
+
var DESKTOP_FAMILIES = /* @__PURE__ */ new Set(["macos", "windows", "gnome", "kde"]);
|
|
44637
|
+
function defaultBranch(family) {
|
|
44638
|
+
if (family === "web")
|
|
44639
|
+
return "ui";
|
|
44640
|
+
return DESKTOP_FAMILIES.has(family) ? void 0 : "native";
|
|
44641
|
+
}
|
|
44642
|
+
function defaultPlatform(family) {
|
|
44643
|
+
if (family === "web")
|
|
44644
|
+
return "web-app";
|
|
44645
|
+
return DESKTOP_FAMILIES.has(family) ? "desktop" : "mobile";
|
|
44646
|
+
}
|
|
44647
|
+
var branchOf = (target) => target.branch ?? defaultBranch(target.family);
|
|
44648
|
+
var platformOf = (target) => target.platform ?? defaultPlatform(target.family);
|
|
44649
|
+
var unique = (values) => [...new Set(values)];
|
|
44650
|
+
function legacyFiles(config2) {
|
|
44651
|
+
const branches = unique(config2.targets.flatMap((target) => branchOf(target) ?? []));
|
|
44652
|
+
const platforms = unique(config2.targets.map(platformOf));
|
|
44653
|
+
const { library, product } = config2.figma;
|
|
44654
|
+
return {
|
|
44655
|
+
libraries: library === void 0 ? [] : [{ key: library, layer: "foundations", branches: branches.length > 0 ? branches : ["ui"], extends: [] }],
|
|
44656
|
+
products: product === void 0 ? [] : platforms.map((platform) => ({ key: product, platform }))
|
|
44657
|
+
};
|
|
44658
|
+
}
|
|
44659
|
+
function designGraph(config2) {
|
|
44660
|
+
const { figma } = config2;
|
|
44661
|
+
const legacy = figma.library !== void 0 || figma.product !== void 0;
|
|
44662
|
+
const { libraries, products } = legacy ? legacyFiles(config2) : { libraries: figma.libraries ?? [], products: figma.products ?? [] };
|
|
44663
|
+
const kits = figma.kits ?? [];
|
|
44664
|
+
const prototypes = figma.prototypes ?? [];
|
|
44665
|
+
const byKey = new Map(libraries.map((library) => [library.key, library]));
|
|
44666
|
+
const closure = (key) => {
|
|
44667
|
+
const out = [];
|
|
44668
|
+
const visit2 = (next) => {
|
|
44669
|
+
if (out.includes(next))
|
|
44670
|
+
return;
|
|
44671
|
+
out.push(next);
|
|
44672
|
+
for (const base of byKey.get(next)?.extends ?? [])
|
|
44673
|
+
visit2(base);
|
|
44674
|
+
};
|
|
44675
|
+
visit2(key);
|
|
44676
|
+
return out;
|
|
44677
|
+
};
|
|
44678
|
+
return {
|
|
44679
|
+
libraries,
|
|
44680
|
+
kits,
|
|
44681
|
+
products,
|
|
44682
|
+
prototypes,
|
|
44683
|
+
legacy,
|
|
44684
|
+
branchOf,
|
|
44685
|
+
platformOf,
|
|
44686
|
+
librariesFor: (target) => {
|
|
44687
|
+
if (legacy)
|
|
44688
|
+
return libraries;
|
|
44689
|
+
const branch = branchOf(target);
|
|
44690
|
+
return libraries.filter((library) => branch !== void 0 && library.branches.includes(branch));
|
|
44691
|
+
},
|
|
44692
|
+
kitsFor: (target) => kits.filter((kit) => kit.family === target.family),
|
|
44693
|
+
closure,
|
|
44694
|
+
multiBranch: (key) => (byKey.get(key)?.branches.length ?? 0) > 1,
|
|
44695
|
+
productOf: (prototypeKey) => {
|
|
44696
|
+
const prototype2 = prototypes.find((candidate) => candidate.key === prototypeKey);
|
|
44697
|
+
return prototype2?.product ?? (products.length === 1 ? products[0]?.key : void 0);
|
|
44698
|
+
}
|
|
44699
|
+
};
|
|
44700
|
+
}
|
|
44701
|
+
function snapshotsFor(input2, target) {
|
|
44702
|
+
const graph = designGraph(input2.config);
|
|
44703
|
+
const branch = target ? graph.branchOf(target) : void 0;
|
|
44704
|
+
const missing = [];
|
|
44705
|
+
const libraries = (target ? graph.librariesFor(target) : graph.libraries).flatMap((library) => {
|
|
44706
|
+
const snapshot = input2.libraries[library.key];
|
|
44707
|
+
if (!snapshot) {
|
|
44708
|
+
missing.push(library.key);
|
|
44709
|
+
return [];
|
|
44710
|
+
}
|
|
44711
|
+
if (!target || !graph.multiBranch(library.key))
|
|
44712
|
+
return [snapshot];
|
|
44713
|
+
const components = snapshot.components.filter((component2) => component2.branch === void 0 || component2.branch === branch);
|
|
44714
|
+
return [{ ...snapshot, components }];
|
|
44715
|
+
});
|
|
44716
|
+
const kits = (target ? graph.kitsFor(target) : graph.kits).flatMap((kit) => {
|
|
44717
|
+
const snapshot = input2.kits[kit.key];
|
|
44718
|
+
if (!snapshot)
|
|
44719
|
+
missing.push(kit.key);
|
|
44720
|
+
return snapshot ? [snapshot] : [];
|
|
44721
|
+
});
|
|
44722
|
+
return { libraries, kits, missing };
|
|
44723
|
+
}
|
|
44724
|
+
|
|
44619
44725
|
// packages/zaku/dist/lib/schema/zaku-config.js
|
|
44620
44726
|
var PLATFORM_FAMILIES = ["web", "ios", "android", "macos", "windows", "gnome", "kde"];
|
|
44727
|
+
var LAYERS = ["foundations", "components"];
|
|
44728
|
+
var BRANCHES = ["ui", "native"];
|
|
44729
|
+
var PLATFORMS = ["web-app", "mobile", "desktop"];
|
|
44621
44730
|
var DEFAULT_INTERACTIVE = [
|
|
44622
44731
|
"Button",
|
|
44623
44732
|
"Button Group",
|
|
@@ -44644,7 +44753,11 @@ var targetSchema = external_exports.object({
|
|
|
44644
44753
|
family: external_exports.enum(PLATFORM_FAMILIES),
|
|
44645
44754
|
name: external_exports.string().regex(/^\S(.*\S)?$/, "a name has no leading or trailing space").refine((name) => !name.includes("/"), "a name has no slash, which separates the parts of a frame name"),
|
|
44646
44755
|
/** The frame size every frame of this target is drawn at; the frame check compares it. */
|
|
44647
|
-
size: external_exports.object({ width: external_exports.number().positive(), height: external_exports.number().positive() }).strict().optional()
|
|
44756
|
+
size: external_exports.object({ width: external_exports.number().positive(), height: external_exports.number().positive() }).strict().optional(),
|
|
44757
|
+
/** The renderer whose libraries its frames draw from; `defaultBranch` in the design graph gives it when left out. */
|
|
44758
|
+
branch: external_exports.enum(BRANCHES).optional(),
|
|
44759
|
+
/** What its frames serve; `defaultPlatform` in the design graph gives it when left out. */
|
|
44760
|
+
platform: external_exports.enum(PLATFORMS).optional()
|
|
44648
44761
|
}).strict();
|
|
44649
44762
|
var DEFAULT_SYSTEM_BARS = {
|
|
44650
44763
|
web: [],
|
|
@@ -44664,7 +44777,33 @@ var budgetSchema = external_exports.object({
|
|
|
44664
44777
|
mcpPerRun: external_exports.number().int().positive().default(30),
|
|
44665
44778
|
reserve: external_exports.number().min(0).max(1).default(0.2)
|
|
44666
44779
|
}).strict();
|
|
44667
|
-
var
|
|
44780
|
+
var fileKey = external_exports.string().min(1);
|
|
44781
|
+
var kitSchema = external_exports.object({ key: fileKey, family: external_exports.enum(PLATFORM_FAMILIES) }).strict();
|
|
44782
|
+
var librarySchema = external_exports.object({
|
|
44783
|
+
key: fileKey,
|
|
44784
|
+
layer: external_exports.enum(LAYERS),
|
|
44785
|
+
branches: external_exports.array(external_exports.enum(BRANCHES)).min(1),
|
|
44786
|
+
/** The libraries and kits this one is built on, by key. */
|
|
44787
|
+
extends: external_exports.array(fileKey).default([])
|
|
44788
|
+
}).strict();
|
|
44789
|
+
var productSchema = external_exports.object({ key: fileKey, platform: external_exports.enum(PLATFORMS) }).strict();
|
|
44790
|
+
var prototypeSchema = external_exports.object({
|
|
44791
|
+
key: fileKey,
|
|
44792
|
+
platform: external_exports.enum(PLATFORMS),
|
|
44793
|
+
/** The product file its frames are copied from; required when there are several. */
|
|
44794
|
+
product: fileKey.optional()
|
|
44795
|
+
}).strict();
|
|
44796
|
+
var files = external_exports.object({
|
|
44797
|
+
library: fileKey.optional(),
|
|
44798
|
+
product: fileKey.optional(),
|
|
44799
|
+
kits: external_exports.array(kitSchema).optional(),
|
|
44800
|
+
libraries: external_exports.array(librarySchema).optional(),
|
|
44801
|
+
products: external_exports.array(productSchema).optional(),
|
|
44802
|
+
prototypes: external_exports.array(prototypeSchema).optional()
|
|
44803
|
+
}).strict();
|
|
44804
|
+
function byRole(figma) {
|
|
44805
|
+
return [figma.kits, figma.libraries, figma.products, figma.prototypes].some((list) => list !== void 0);
|
|
44806
|
+
}
|
|
44668
44807
|
var shadcnSystem = external_exports.object({ preset: external_exports.string().min(1) }).strict();
|
|
44669
44808
|
var tokenFiles = external_exports.array(external_exports.string().min(1)).min(1);
|
|
44670
44809
|
var resolverInputs = external_exports.record(external_exports.string(), external_exports.string());
|
|
@@ -44716,7 +44855,7 @@ var copySchema = external_exports.object({
|
|
|
44716
44855
|
locales: external_exports.array(external_exports.string().refine(writtenInAScript, "a BCP 47 language tag, such as en or vi")).min(1).default(["en"]),
|
|
44717
44856
|
currencies: external_exports.array(external_exports.string().refine((code) => Intl.supportedValuesOf("currency").includes(code), "an ISO 4217 code, such as VND or USD")).default([])
|
|
44718
44857
|
}).strict();
|
|
44719
|
-
var
|
|
44858
|
+
var configShape = external_exports.object({
|
|
44720
44859
|
product: external_exports.string().min(1),
|
|
44721
44860
|
designSystem: designSystemSchema,
|
|
44722
44861
|
figma: files.default({}),
|
|
@@ -44728,7 +44867,8 @@ var zakuConfigSchema = external_exports.object({
|
|
|
44728
44867
|
budget: budgetSchema.default({ mcpPerDay: 200, mcpPerRun: 30, reserve: 0.2 }),
|
|
44729
44868
|
recipe: recipeSchema.optional(),
|
|
44730
44869
|
copy: copySchema.default(DEFAULT_COPY)
|
|
44731
|
-
}).strict()
|
|
44870
|
+
}).strict();
|
|
44871
|
+
var zakuConfigSchema = configShape.superRefine((config2, ctx) => {
|
|
44732
44872
|
for (const key of ["id", "name"]) {
|
|
44733
44873
|
const seen = /* @__PURE__ */ new Set();
|
|
44734
44874
|
config2.targets.forEach((target, index) => {
|
|
@@ -44742,7 +44882,112 @@ var zakuConfigSchema = external_exports.object({
|
|
|
44742
44882
|
seen.add(target[key]);
|
|
44743
44883
|
});
|
|
44744
44884
|
}
|
|
44885
|
+
if (byRole(config2.figma))
|
|
44886
|
+
refineFilesByRole(config2, ctx);
|
|
44745
44887
|
});
|
|
44888
|
+
function refineFilesByRole(config2, ctx) {
|
|
44889
|
+
const { figma } = config2;
|
|
44890
|
+
if (figma.library !== void 0 || figma.product !== void 0) {
|
|
44891
|
+
ctx.addIssue({
|
|
44892
|
+
code: "custom",
|
|
44893
|
+
path: ["figma"],
|
|
44894
|
+
message: "figma.library and figma.product describe one library and one product; list files by role instead"
|
|
44895
|
+
});
|
|
44896
|
+
}
|
|
44897
|
+
const kits = figma.kits ?? [];
|
|
44898
|
+
const libraries = figma.libraries ?? [];
|
|
44899
|
+
const products = figma.products ?? [];
|
|
44900
|
+
const seen = /* @__PURE__ */ new Set();
|
|
44901
|
+
const lists = [
|
|
44902
|
+
["kits", kits],
|
|
44903
|
+
["libraries", libraries],
|
|
44904
|
+
["products", products],
|
|
44905
|
+
["prototypes", figma.prototypes ?? []]
|
|
44906
|
+
];
|
|
44907
|
+
for (const [list, entries] of lists) {
|
|
44908
|
+
entries.forEach((entry, index) => {
|
|
44909
|
+
if (seen.has(entry.key))
|
|
44910
|
+
ctx.addIssue({
|
|
44911
|
+
code: "custom",
|
|
44912
|
+
path: ["figma", list, index, "key"],
|
|
44913
|
+
message: `a second file with key ${entry.key}`
|
|
44914
|
+
});
|
|
44915
|
+
seen.add(entry.key);
|
|
44916
|
+
});
|
|
44917
|
+
}
|
|
44918
|
+
const byKey = new Map(libraries.map((library) => [library.key, library]));
|
|
44919
|
+
const kitKeys = new Set(kits.map((kit) => kit.key));
|
|
44920
|
+
libraries.forEach((library, index) => {
|
|
44921
|
+
const path2 = ["figma", "libraries", index, "extends"];
|
|
44922
|
+
for (const key of library.extends) {
|
|
44923
|
+
const base = byKey.get(key);
|
|
44924
|
+
if (!base && !kitKeys.has(key)) {
|
|
44925
|
+
ctx.addIssue({
|
|
44926
|
+
code: "custom",
|
|
44927
|
+
path: path2,
|
|
44928
|
+
message: `${library.key} extends ${key}, which is no library or kit listed`
|
|
44929
|
+
});
|
|
44930
|
+
} else if (base?.layer === "components" && library.layer === "foundations") {
|
|
44931
|
+
ctx.addIssue({ code: "custom", path: path2, message: `foundations ${library.key} extends components ${key}` });
|
|
44932
|
+
} else if (base && !base.branches.some((branch) => library.branches.includes(branch))) {
|
|
44933
|
+
ctx.addIssue({
|
|
44934
|
+
code: "custom",
|
|
44935
|
+
path: path2,
|
|
44936
|
+
message: `${library.key} extends ${key}, which holds none of its branches`
|
|
44937
|
+
});
|
|
44938
|
+
}
|
|
44939
|
+
}
|
|
44940
|
+
});
|
|
44941
|
+
const cycle = findCycle(libraries);
|
|
44942
|
+
if (cycle)
|
|
44943
|
+
ctx.addIssue({ code: "custom", path: ["figma", "libraries"], message: `extends comes back: ${cycle}` });
|
|
44944
|
+
(figma.prototypes ?? []).forEach((prototype2, index) => {
|
|
44945
|
+
const path2 = ["figma", "prototypes", index];
|
|
44946
|
+
if (prototype2.product === void 0) {
|
|
44947
|
+
if (products.length > 1)
|
|
44948
|
+
ctx.addIssue({ code: "custom", path: [...path2, "product"], message: "name the product its frames come from" });
|
|
44949
|
+
return;
|
|
44950
|
+
}
|
|
44951
|
+
const product = products.find((candidate) => candidate.key === prototype2.product);
|
|
44952
|
+
if (!product) {
|
|
44953
|
+
ctx.addIssue({ code: "custom", path: [...path2, "product"], message: `no product with key ${prototype2.product}` });
|
|
44954
|
+
} else if (product.platform !== prototype2.platform) {
|
|
44955
|
+
ctx.addIssue({
|
|
44956
|
+
code: "custom",
|
|
44957
|
+
path: [...path2, "platform"],
|
|
44958
|
+
message: `${prototype2.platform}, and its product serves ${product.platform}`
|
|
44959
|
+
});
|
|
44960
|
+
}
|
|
44961
|
+
});
|
|
44962
|
+
config2.targets.forEach((target, index) => {
|
|
44963
|
+
const branch = target.branch ?? defaultBranch(target.family);
|
|
44964
|
+
const path2 = ["targets", index, "branch"];
|
|
44965
|
+
if (branch === void 0) {
|
|
44966
|
+
ctx.addIssue({ code: "custom", path: path2, message: `a ${target.family} target names its branch, ui or native` });
|
|
44967
|
+
} else if (libraries.length > 0 && !libraries.some((library) => library.branches.includes(branch))) {
|
|
44968
|
+
ctx.addIssue({ code: "custom", path: path2, message: `no library holds the ${branch} branch` });
|
|
44969
|
+
}
|
|
44970
|
+
});
|
|
44971
|
+
}
|
|
44972
|
+
function findCycle(libraries) {
|
|
44973
|
+
const byKey = new Map(libraries.map((library) => [library.key, library]));
|
|
44974
|
+
const visit2 = (key, path2) => {
|
|
44975
|
+
if (path2.includes(key))
|
|
44976
|
+
return [...path2.slice(path2.indexOf(key)), key].join(" -> ");
|
|
44977
|
+
for (const next of byKey.get(key)?.extends ?? []) {
|
|
44978
|
+
const found = visit2(next, [...path2, key]);
|
|
44979
|
+
if (found)
|
|
44980
|
+
return found;
|
|
44981
|
+
}
|
|
44982
|
+
return void 0;
|
|
44983
|
+
};
|
|
44984
|
+
for (const library of libraries) {
|
|
44985
|
+
const found = visit2(library.key, []);
|
|
44986
|
+
if (found)
|
|
44987
|
+
return found;
|
|
44988
|
+
}
|
|
44989
|
+
return void 0;
|
|
44990
|
+
}
|
|
44746
44991
|
|
|
44747
44992
|
// packages/zaku/dist/lib/repositories/design-file.js
|
|
44748
44993
|
var import_yaml = __toESM(require_dist(), 1);
|
|
@@ -44783,6 +45028,12 @@ async function writeDesignFile(path2, value) {
|
|
|
44783
45028
|
|
|
44784
45029
|
// packages/zaku/dist/lib/repositories/design-paths.js
|
|
44785
45030
|
import { join as join2 } from "node:path";
|
|
45031
|
+
function librarySnapshotDir(paths, key) {
|
|
45032
|
+
if (key === null)
|
|
45033
|
+
return paths;
|
|
45034
|
+
const library = join2(paths.library, key);
|
|
45035
|
+
return { root: paths.root, library, libraryIndex: join2(library, "index.json"), legacyLibrary: null };
|
|
45036
|
+
}
|
|
44786
45037
|
function designPaths(root) {
|
|
44787
45038
|
return {
|
|
44788
45039
|
root,
|
|
@@ -44790,12 +45041,18 @@ function designPaths(root) {
|
|
|
44790
45041
|
maps: join2(root, "map"),
|
|
44791
45042
|
outline: join2(root, "outline"),
|
|
44792
45043
|
unmapped: join2(root, "outline", "unmapped.yaml"),
|
|
44793
|
-
library: join2(root, "library
|
|
45044
|
+
library: join2(root, "library"),
|
|
45045
|
+
libraryIndex: join2(root, "library", "index.json"),
|
|
45046
|
+
legacyLibrary: join2(root, "library.json"),
|
|
44794
45047
|
tokens: join2(root, "tokens.json"),
|
|
44795
45048
|
recipe: join2(root, "recipe.json")
|
|
44796
45049
|
};
|
|
44797
45050
|
}
|
|
44798
45051
|
|
|
45052
|
+
// packages/zaku/dist/lib/repositories/library-snapshot.js
|
|
45053
|
+
import { mkdir, readdir, readFile as readFile2, rename as rename2, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
45054
|
+
import { join as join3, relative } from "node:path";
|
|
45055
|
+
|
|
44799
45056
|
// packages/zaku/dist/lib/domain/library.js
|
|
44800
45057
|
var rgbaSchema = external_exports.object({ r: external_exports.number(), g: external_exports.number(), b: external_exports.number(), a: external_exports.number() }).strict();
|
|
44801
45058
|
var libraryItemSchema = external_exports.object({
|
|
@@ -44820,8 +45077,13 @@ var libraryItemSchema = external_exports.object({
|
|
|
44820
45077
|
fontFamily: external_exports.string().nullable(),
|
|
44821
45078
|
textStyleKey: external_exports.string().nullable(),
|
|
44822
45079
|
componentKey: external_exports.string().nullable(),
|
|
44823
|
-
bindings: external_exports.record(external_exports.string(), external_exports.string().nullable())
|
|
45080
|
+
bindings: external_exports.record(external_exports.string(), external_exports.string().nullable()),
|
|
45081
|
+
/** Every variable the layer's own properties are bound to, by id without its `VariableID:` prefix. */
|
|
45082
|
+
variableIds: external_exports.array(external_exports.string()).optional(),
|
|
45083
|
+
effectStyleKey: external_exports.string().optional()
|
|
44824
45084
|
}).strict();
|
|
45085
|
+
var variableKeySchema = external_exports.object({ key: external_exports.string(), local: external_exports.boolean() }).strict();
|
|
45086
|
+
var effectStyleSchema = external_exports.object({ key: external_exports.string(), name: external_exports.string() }).strict();
|
|
44825
45087
|
var libraryVariantSchema = external_exports.object({
|
|
44826
45088
|
key: external_exports.string(),
|
|
44827
45089
|
name: external_exports.string(),
|
|
@@ -44832,6 +45094,8 @@ var libraryComponentSchema = external_exports.object({
|
|
|
44832
45094
|
name: external_exports.string(),
|
|
44833
45095
|
key: external_exports.string(),
|
|
44834
45096
|
page: external_exports.string(),
|
|
45097
|
+
/** The branch of the view that holds it, in a file that holds several; none where it serves every branch. */
|
|
45098
|
+
branch: external_exports.string().optional(),
|
|
44835
45099
|
codePath: external_exports.string().nullable(),
|
|
44836
45100
|
map: external_exports.object({ props: external_exports.record(external_exports.string(), external_exports.string()), parts: external_exports.record(external_exports.string(), external_exports.string()) }).strict().nullable(),
|
|
44837
45101
|
variants: external_exports.array(libraryVariantSchema).min(1)
|
|
@@ -44851,12 +45115,22 @@ var libraryPartSchema = external_exports.object({
|
|
|
44851
45115
|
exportedAt: external_exports.string(),
|
|
44852
45116
|
components: external_exports.array(libraryComponentSchema),
|
|
44853
45117
|
textStyles: external_exports.array(textStyleSchema),
|
|
44854
|
-
tokens: external_exports.array(tokenSnapshotSchema)
|
|
45118
|
+
tokens: external_exports.array(tokenSnapshotSchema),
|
|
45119
|
+
/**
|
|
45120
|
+
* What the items' references resolve against, absent from a snapshot saved before they were recorded: each
|
|
45121
|
+
* variable id's key, the file's effect styles, and the keys of the components the file holds unpublished.
|
|
45122
|
+
*/
|
|
45123
|
+
variableKeys: external_exports.record(external_exports.string(), variableKeySchema).optional(),
|
|
45124
|
+
effectStyles: external_exports.array(effectStyleSchema).optional(),
|
|
45125
|
+
localComponents: external_exports.array(external_exports.string()).optional()
|
|
44855
45126
|
}).strict();
|
|
44856
45127
|
var variablePartSchema = external_exports.object({
|
|
44857
45128
|
exportedAt: external_exports.string(),
|
|
44858
45129
|
variables: external_exports.record(external_exports.string(), external_exports.string()),
|
|
44859
45130
|
textStyles: external_exports.array(textStyleSchema),
|
|
45131
|
+
/** Each variable's key, keyed like `variables`. */
|
|
45132
|
+
variableKeys: external_exports.record(external_exports.string(), variableKeySchema).optional(),
|
|
45133
|
+
effectStyles: external_exports.array(effectStyleSchema).optional(),
|
|
44860
45134
|
tokens: external_exports.array(external_exports.object({
|
|
44861
45135
|
combo: external_exports.record(external_exports.string(), external_exports.string()),
|
|
44862
45136
|
values: external_exports.record(external_exports.string(), external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean()]))
|
|
@@ -44867,12 +45141,309 @@ var variablePartSchema = external_exports.object({
|
|
|
44867
45141
|
key: external_exports.string(),
|
|
44868
45142
|
name: external_exports.string(),
|
|
44869
45143
|
page: external_exports.string(),
|
|
45144
|
+
/** The view that holds it: the frame directly on its page, where it sits in one. */
|
|
45145
|
+
frame: external_exports.string().optional(),
|
|
44870
45146
|
description: external_exports.string(),
|
|
44871
45147
|
set: external_exports.boolean()
|
|
44872
45148
|
}).strict()).optional()
|
|
44873
45149
|
}).strict();
|
|
45150
|
+
var kitSnapshotSchema = external_exports.object({
|
|
45151
|
+
key: external_exports.string(),
|
|
45152
|
+
family: external_exports.string(),
|
|
45153
|
+
components: external_exports.array(external_exports.object({ key: external_exports.string(), name: external_exports.string() }).strict())
|
|
45154
|
+
}).strict();
|
|
44874
45155
|
var librarySnapshotSchema = libraryPartSchema.extend({ source: external_exports.string(), version: external_exports.string() }).strict();
|
|
44875
45156
|
|
|
45157
|
+
// packages/zaku/dist/lib/domain/library-files.js
|
|
45158
|
+
import { isDeepStrictEqual } from "node:util";
|
|
45159
|
+
var storedItemSchema = libraryItemSchema.partial().required({ nodeId: true, path: true, type: true, width: true, height: true }).extend({ bindings: libraryItemSchema.shape.bindings.optional(), glyph: rgbaSchema.optional() }).strict();
|
|
45160
|
+
var libraryFileSchema = external_exports.object({
|
|
45161
|
+
name: external_exports.string(),
|
|
45162
|
+
key: external_exports.string(),
|
|
45163
|
+
variants: external_exports.array(external_exports.object({
|
|
45164
|
+
key: external_exports.string(),
|
|
45165
|
+
/** The items in the first mode of the index's tokens. */
|
|
45166
|
+
items: external_exports.array(storedItemSchema),
|
|
45167
|
+
/** Only the modes whose stored items differ from the first. */
|
|
45168
|
+
modes: external_exports.array(external_exports.object({ combo: external_exports.record(external_exports.string(), external_exports.string()), items: external_exports.array(storedItemSchema) }).strict()).optional()
|
|
45169
|
+
}).strict())
|
|
45170
|
+
}).strict();
|
|
45171
|
+
var libraryIndexSchema = librarySnapshotSchema.extend({
|
|
45172
|
+
components: external_exports.array(libraryComponentSchema.omit({ variants: true }).extend({
|
|
45173
|
+
file: external_exports.string(),
|
|
45174
|
+
variants: external_exports.array(libraryVariantSchema.pick({ key: true, name: true, props: true }).strict())
|
|
45175
|
+
}).strict())
|
|
45176
|
+
}).strict();
|
|
45177
|
+
var NULLABLE = [
|
|
45178
|
+
"fill",
|
|
45179
|
+
"stroke",
|
|
45180
|
+
"textColor",
|
|
45181
|
+
"padding",
|
|
45182
|
+
"gap",
|
|
45183
|
+
"radii",
|
|
45184
|
+
"strokeWeights",
|
|
45185
|
+
"fontSize",
|
|
45186
|
+
"fontFamily",
|
|
45187
|
+
"textStyleKey",
|
|
45188
|
+
"componentKey"
|
|
45189
|
+
];
|
|
45190
|
+
var RESOLVED = ["fill", "stroke", "textColor", "glyph", "radii"];
|
|
45191
|
+
function colour(name, values) {
|
|
45192
|
+
const value = name ? values[name] : void 0;
|
|
45193
|
+
return value !== void 0 && typeof value === "object" ? value : null;
|
|
45194
|
+
}
|
|
45195
|
+
function expandItem(stored, values) {
|
|
45196
|
+
const bindings = {
|
|
45197
|
+
fill: null,
|
|
45198
|
+
stroke: null,
|
|
45199
|
+
textColor: null,
|
|
45200
|
+
radius: null,
|
|
45201
|
+
...stored.bindings
|
|
45202
|
+
};
|
|
45203
|
+
const radius = bindings.radius ? values[bindings.radius] : void 0;
|
|
45204
|
+
const glyph = stored.glyph ?? (bindings["glyph"] ? colour(bindings["glyph"], values) : null);
|
|
45205
|
+
return {
|
|
45206
|
+
nodeId: stored.nodeId,
|
|
45207
|
+
path: stored.path,
|
|
45208
|
+
type: stored.type,
|
|
45209
|
+
fill: stored.fill !== void 0 ? stored.fill : colour(bindings.fill, values),
|
|
45210
|
+
stroke: stored.stroke !== void 0 ? stored.stroke : colour(bindings.stroke, values),
|
|
45211
|
+
textColor: stored.textColor !== void 0 ? stored.textColor : colour(bindings.textColor, values),
|
|
45212
|
+
...glyph ? { glyph } : {},
|
|
45213
|
+
width: stored.width,
|
|
45214
|
+
height: stored.height,
|
|
45215
|
+
padding: stored.padding ?? null,
|
|
45216
|
+
gap: stored.gap ?? null,
|
|
45217
|
+
radii: stored.radii !== void 0 ? stored.radii : typeof radius === "number" ? [radius, radius, radius, radius] : null,
|
|
45218
|
+
strokeWeights: stored.strokeWeights ?? null,
|
|
45219
|
+
fontSize: stored.fontSize ?? null,
|
|
45220
|
+
fontFamily: stored.fontFamily ?? null,
|
|
45221
|
+
textStyleKey: stored.textStyleKey ?? null,
|
|
45222
|
+
componentKey: stored.componentKey ?? null,
|
|
45223
|
+
bindings,
|
|
45224
|
+
...stored.variableIds ? { variableIds: stored.variableIds } : {},
|
|
45225
|
+
...stored.effectStyleKey ? { effectStyleKey: stored.effectStyleKey } : {}
|
|
45226
|
+
};
|
|
45227
|
+
}
|
|
45228
|
+
function compactItem(item, values) {
|
|
45229
|
+
const stored = {
|
|
45230
|
+
nodeId: item.nodeId,
|
|
45231
|
+
path: item.path,
|
|
45232
|
+
type: item.type,
|
|
45233
|
+
width: item.width,
|
|
45234
|
+
height: item.height
|
|
45235
|
+
};
|
|
45236
|
+
for (const field of NULLABLE)
|
|
45237
|
+
if (item[field] !== null)
|
|
45238
|
+
stored[field] = item[field];
|
|
45239
|
+
if (item.glyph)
|
|
45240
|
+
stored["glyph"] = item.glyph;
|
|
45241
|
+
if (item.variableIds)
|
|
45242
|
+
stored["variableIds"] = item.variableIds;
|
|
45243
|
+
if (item.effectStyleKey)
|
|
45244
|
+
stored["effectStyleKey"] = item.effectStyleKey;
|
|
45245
|
+
const bindings = Object.fromEntries(Object.entries(item.bindings).filter(([name, value]) => value !== null || name === "glyph"));
|
|
45246
|
+
if (Object.keys(bindings).length > 0)
|
|
45247
|
+
stored["bindings"] = bindings;
|
|
45248
|
+
for (const field of RESOLVED) {
|
|
45249
|
+
if (!(field in stored))
|
|
45250
|
+
continue;
|
|
45251
|
+
const without = { ...stored };
|
|
45252
|
+
delete without[field];
|
|
45253
|
+
if (isDeepStrictEqual(expandItem(without, values), item))
|
|
45254
|
+
delete stored[field];
|
|
45255
|
+
}
|
|
45256
|
+
return isDeepStrictEqual(expandItem(stored, values), item) ? stored : item;
|
|
45257
|
+
}
|
|
45258
|
+
function comboKey(combo) {
|
|
45259
|
+
return JSON.stringify(Object.entries(combo).sort(([a], [b]) => a.localeCompare(b)));
|
|
45260
|
+
}
|
|
45261
|
+
function fileName(name, key, taken) {
|
|
45262
|
+
const slug2 = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "component";
|
|
45263
|
+
const file2 = taken.has(slug2) ? `${slug2}-${key.slice(0, 8)}` : slug2;
|
|
45264
|
+
taken.add(file2);
|
|
45265
|
+
return `components/${file2}.json`;
|
|
45266
|
+
}
|
|
45267
|
+
function splitLibrary(snapshot) {
|
|
45268
|
+
const valuesOf = new Map(snapshot.tokens.map((token) => [comboKey(token.combo), token.values]));
|
|
45269
|
+
const taken = /* @__PURE__ */ new Set();
|
|
45270
|
+
const files2 = /* @__PURE__ */ new Map();
|
|
45271
|
+
const components = [];
|
|
45272
|
+
for (const { variants, ...component2 } of snapshot.components) {
|
|
45273
|
+
const file2 = fileName(component2.name, component2.key, taken);
|
|
45274
|
+
files2.set(file2, {
|
|
45275
|
+
name: component2.name,
|
|
45276
|
+
key: component2.key,
|
|
45277
|
+
variants: variants.map((variant) => {
|
|
45278
|
+
const stored = variant.modes.map((mode) => ({
|
|
45279
|
+
combo: mode.combo,
|
|
45280
|
+
items: mode.items.map((item) => compactItem(item, valuesOf.get(comboKey(mode.combo)) ?? {}))
|
|
45281
|
+
}));
|
|
45282
|
+
const [first, ...rest] = stored;
|
|
45283
|
+
const modes = rest.filter((mode) => !isDeepStrictEqual(mode.items, first?.items));
|
|
45284
|
+
return { key: variant.key, items: first?.items ?? [], ...modes.length > 0 ? { modes } : {} };
|
|
45285
|
+
})
|
|
45286
|
+
});
|
|
45287
|
+
components.push({
|
|
45288
|
+
...component2,
|
|
45289
|
+
file: file2,
|
|
45290
|
+
variants: variants.map(({ key, name, props }) => ({ key, name, props }))
|
|
45291
|
+
});
|
|
45292
|
+
}
|
|
45293
|
+
return { index: { ...snapshot, components }, files: files2 };
|
|
45294
|
+
}
|
|
45295
|
+
function joinLibrary(index, files2) {
|
|
45296
|
+
return {
|
|
45297
|
+
...index,
|
|
45298
|
+
components: index.components.map(({ file: file2, variants, ...component2 }) => {
|
|
45299
|
+
const stored = files2.get(file2);
|
|
45300
|
+
if (!stored)
|
|
45301
|
+
throw new Error(`library/${file2} is not loaded`);
|
|
45302
|
+
return {
|
|
45303
|
+
...component2,
|
|
45304
|
+
variants: variants.map((variant, at) => {
|
|
45305
|
+
const items = stored.variants[at];
|
|
45306
|
+
return {
|
|
45307
|
+
...variant,
|
|
45308
|
+
modes: index.tokens.map((token) => ({
|
|
45309
|
+
combo: token.combo,
|
|
45310
|
+
items: (items?.modes?.find((mode) => comboKey(mode.combo) === comboKey(token.combo))?.items ?? items?.items ?? []).map((item) => expandItem(item, token.values))
|
|
45311
|
+
}))
|
|
45312
|
+
};
|
|
45313
|
+
})
|
|
45314
|
+
};
|
|
45315
|
+
})
|
|
45316
|
+
};
|
|
45317
|
+
}
|
|
45318
|
+
var ONE_LINE = 100;
|
|
45319
|
+
function write(value, pad, key) {
|
|
45320
|
+
const line = JSON.stringify(value);
|
|
45321
|
+
if (value === null || typeof value !== "object" || line.length <= ONE_LINE)
|
|
45322
|
+
return line;
|
|
45323
|
+
const inner = `${pad} `;
|
|
45324
|
+
if (Array.isArray(value)) {
|
|
45325
|
+
if (value.length === 0)
|
|
45326
|
+
return "[]";
|
|
45327
|
+
const element = (child) => key === "items" ? JSON.stringify(child) : write(child, inner, null);
|
|
45328
|
+
return `[
|
|
45329
|
+
${value.map((child) => `${inner}${element(child)}`).join(",\n")}
|
|
45330
|
+
${pad}]`;
|
|
45331
|
+
}
|
|
45332
|
+
const entries = Object.entries(value).filter(([, child]) => child !== void 0);
|
|
45333
|
+
if (entries.length === 0)
|
|
45334
|
+
return "{}";
|
|
45335
|
+
return `{
|
|
45336
|
+
${entries.map(([name, child]) => `${inner}${JSON.stringify(name)}: ${write(child, inner, name)}`).join(",\n")}
|
|
45337
|
+
${pad}}`;
|
|
45338
|
+
}
|
|
45339
|
+
function formatLibraryFile(value) {
|
|
45340
|
+
return `${write(value, "", null)}
|
|
45341
|
+
`;
|
|
45342
|
+
}
|
|
45343
|
+
|
|
45344
|
+
// packages/zaku/dist/lib/repositories/library-snapshot.js
|
|
45345
|
+
async function readText(path2) {
|
|
45346
|
+
try {
|
|
45347
|
+
return await readFile2(path2, "utf8");
|
|
45348
|
+
} catch (error62) {
|
|
45349
|
+
if (error62.code === "ENOENT")
|
|
45350
|
+
return null;
|
|
45351
|
+
throw error62;
|
|
45352
|
+
}
|
|
45353
|
+
}
|
|
45354
|
+
async function writeText(path2, text) {
|
|
45355
|
+
const temporary = `${path2}.${process.pid}.tmp`;
|
|
45356
|
+
await writeFile2(temporary, text);
|
|
45357
|
+
await rename2(temporary, path2);
|
|
45358
|
+
}
|
|
45359
|
+
async function readLibrarySnapshot(paths) {
|
|
45360
|
+
const index = await readOptionalDesignFile(paths.libraryIndex, libraryIndexSchema);
|
|
45361
|
+
if (!index)
|
|
45362
|
+
return paths.legacyLibrary ? readOptionalDesignFile(paths.legacyLibrary, librarySnapshotSchema) : null;
|
|
45363
|
+
const files2 = /* @__PURE__ */ new Map();
|
|
45364
|
+
for (const component2 of index.components) {
|
|
45365
|
+
const path2 = join3(paths.library, component2.file);
|
|
45366
|
+
const text = await readText(path2);
|
|
45367
|
+
if (text === null)
|
|
45368
|
+
throw new DesignFileInvalid(path2, ["the index names it and it is missing; run zaku library save"]);
|
|
45369
|
+
const file2 = parseDesignFile(path2, text, libraryFileSchema);
|
|
45370
|
+
const keys = file2.variants.map((variant) => variant.key);
|
|
45371
|
+
if (keys.join("\n") !== component2.variants.map((variant) => variant.key).join("\n")) {
|
|
45372
|
+
throw new DesignFileInvalid(path2, ["its variants are not the index's; run zaku library save"]);
|
|
45373
|
+
}
|
|
45374
|
+
files2.set(component2.file, file2);
|
|
45375
|
+
}
|
|
45376
|
+
return joinLibrary(index, files2);
|
|
45377
|
+
}
|
|
45378
|
+
async function writeLibrarySnapshot(paths, snapshot) {
|
|
45379
|
+
const { index, files: files2 } = splitLibrary(snapshot);
|
|
45380
|
+
const directory = join3(paths.library, "components");
|
|
45381
|
+
await mkdir(directory, { recursive: true });
|
|
45382
|
+
const written = [];
|
|
45383
|
+
let unchanged = 0;
|
|
45384
|
+
for (const [file2, content] of files2) {
|
|
45385
|
+
const path2 = join3(paths.library, file2);
|
|
45386
|
+
const text = formatLibraryFile(content);
|
|
45387
|
+
if (await readText(path2) === text) {
|
|
45388
|
+
unchanged += 1;
|
|
45389
|
+
continue;
|
|
45390
|
+
}
|
|
45391
|
+
await writeText(path2, text);
|
|
45392
|
+
written.push(file2);
|
|
45393
|
+
}
|
|
45394
|
+
const removed = [];
|
|
45395
|
+
for (const name of (await readdir(directory)).sort()) {
|
|
45396
|
+
const file2 = `components/${name}`;
|
|
45397
|
+
if (!name.endsWith(".json") || files2.has(file2))
|
|
45398
|
+
continue;
|
|
45399
|
+
await rm(join3(directory, name));
|
|
45400
|
+
removed.push(file2);
|
|
45401
|
+
}
|
|
45402
|
+
await writeText(paths.libraryIndex, formatLibraryFile(index));
|
|
45403
|
+
if (paths.legacyLibrary && await readText(paths.legacyLibrary) !== null) {
|
|
45404
|
+
await rm(paths.legacyLibrary);
|
|
45405
|
+
removed.push(relative(paths.root, paths.legacyLibrary));
|
|
45406
|
+
}
|
|
45407
|
+
return { written, unchanged, removed };
|
|
45408
|
+
}
|
|
45409
|
+
async function writeKitSnapshot(paths, kit) {
|
|
45410
|
+
await mkdir(paths.library, { recursive: true });
|
|
45411
|
+
const path2 = join3(paths.library, "kit.json");
|
|
45412
|
+
await writeText(path2, formatLibraryFile(kit));
|
|
45413
|
+
return path2;
|
|
45414
|
+
}
|
|
45415
|
+
async function readDesignSnapshots(paths, config2) {
|
|
45416
|
+
const graph = designGraph(config2);
|
|
45417
|
+
const libraries = {};
|
|
45418
|
+
const kits = {};
|
|
45419
|
+
const errors = [];
|
|
45420
|
+
const attempt = async (read) => {
|
|
45421
|
+
try {
|
|
45422
|
+
await read();
|
|
45423
|
+
} catch (error62) {
|
|
45424
|
+
if (!(error62 instanceof DesignFileInvalid))
|
|
45425
|
+
throw error62;
|
|
45426
|
+
errors.push(error62);
|
|
45427
|
+
}
|
|
45428
|
+
};
|
|
45429
|
+
for (const library of graph.libraries) {
|
|
45430
|
+
await attempt(async () => {
|
|
45431
|
+
const snapshot = await readLibrarySnapshot(librarySnapshotDir(paths, graph.legacy ? null : library.key));
|
|
45432
|
+
if (snapshot)
|
|
45433
|
+
libraries[library.key] = snapshot;
|
|
45434
|
+
});
|
|
45435
|
+
}
|
|
45436
|
+
for (const kit of graph.kits) {
|
|
45437
|
+
await attempt(async () => {
|
|
45438
|
+
const path2 = join3(librarySnapshotDir(paths, kit.key).library, "kit.json");
|
|
45439
|
+
const snapshot = await readOptionalDesignFile(path2, kitSnapshotSchema);
|
|
45440
|
+
if (snapshot)
|
|
45441
|
+
kits[kit.key] = snapshot;
|
|
45442
|
+
});
|
|
45443
|
+
}
|
|
45444
|
+
return { libraries, kits, errors };
|
|
45445
|
+
}
|
|
45446
|
+
|
|
44876
45447
|
// packages/zaku/dist/lib/adapters/figma-rest-library.js
|
|
44877
45448
|
var DOCUMENTATION_PREFIXES = ["DS/"];
|
|
44878
45449
|
var round3 = (value) => Math.round(value * 1e4) / 1e4;
|
|
@@ -44945,6 +45516,23 @@ function strokeWeightsOf(node2) {
|
|
|
44945
45516
|
const weight = node2.strokeWeight ?? 0;
|
|
44946
45517
|
return [weight, weight, weight, weight];
|
|
44947
45518
|
}
|
|
45519
|
+
function aliasIds(node2) {
|
|
45520
|
+
const out = [];
|
|
45521
|
+
const visit2 = (value) => {
|
|
45522
|
+
if (Array.isArray(value))
|
|
45523
|
+
value.forEach(visit2);
|
|
45524
|
+
else if (value && typeof value === "object") {
|
|
45525
|
+
if ("id" in value && typeof value.id === "string")
|
|
45526
|
+
out.push(value.id.replace(/^VariableID:/, ""));
|
|
45527
|
+
else
|
|
45528
|
+
Object.values(value).forEach(visit2);
|
|
45529
|
+
}
|
|
45530
|
+
};
|
|
45531
|
+
visit2(node2.boundVariables);
|
|
45532
|
+
for (const paint of [...node2.fills ?? [], ...node2.strokes ?? []])
|
|
45533
|
+
visit2(paint.boundVariables);
|
|
45534
|
+
return [...new Set(out)];
|
|
45535
|
+
}
|
|
44948
45536
|
var GLYPH_TYPES = /* @__PURE__ */ new Set(["VECTOR", "BOOLEAN_OPERATION", "LINE", "ELLIPSE", "POLYGON", "STAR"]);
|
|
44949
45537
|
function glyphOf(instance, at) {
|
|
44950
45538
|
let text = false;
|
|
@@ -44984,6 +45572,9 @@ function itemsOf(root, at) {
|
|
|
44984
45572
|
const textStyle = node2.styles?.["text"];
|
|
44985
45573
|
const glyph = path2 !== "" && node2.type === "INSTANCE" ? glyphOf(node2, at) : null;
|
|
44986
45574
|
const componentId = node2.type === "INSTANCE" ? node2.componentId : path2 === "" ? node2.id : void 0;
|
|
45575
|
+
const variableIds = aliasIds(node2);
|
|
45576
|
+
const effectStyle = node2.styles?.["effect"];
|
|
45577
|
+
const effectStyleKey = effectStyle ? at.entry.styles[effectStyle]?.key : void 0;
|
|
44987
45578
|
out.push({
|
|
44988
45579
|
nodeId: node2.id,
|
|
44989
45580
|
path: path2,
|
|
@@ -45008,7 +45599,9 @@ function itemsOf(root, at) {
|
|
|
45008
45599
|
textColor: isText ? fill.binding : null,
|
|
45009
45600
|
radius: radiusName,
|
|
45010
45601
|
...glyph?.value ? { glyph: glyph.binding } : {}
|
|
45011
|
-
}
|
|
45602
|
+
},
|
|
45603
|
+
...variableIds.length > 0 ? { variableIds } : {},
|
|
45604
|
+
...effectStyleKey ? { effectStyleKey } : {}
|
|
45012
45605
|
});
|
|
45013
45606
|
if (path2 === "" || node2.type !== "INSTANCE") {
|
|
45014
45607
|
for (const child of node2.children ?? [])
|
|
@@ -45027,28 +45620,55 @@ function asPublished(component2) {
|
|
|
45027
45620
|
containing_frame: { pageName: component2.page }
|
|
45028
45621
|
};
|
|
45029
45622
|
}
|
|
45623
|
+
function viewBranch(view, branches) {
|
|
45624
|
+
const prefix = view?.split(" / ")[0];
|
|
45625
|
+
return view?.includes(" / ") && prefix !== void 0 && branches.includes(prefix) ? prefix : void 0;
|
|
45626
|
+
}
|
|
45627
|
+
function viewsByPage(document) {
|
|
45628
|
+
return new Map((document.children ?? []).map((page) => [
|
|
45629
|
+
page.name,
|
|
45630
|
+
(page.children ?? []).flatMap((view) => view.absoluteBoundingBox ? [{ name: view.name, box: view.absoluteBoundingBox }] : [])
|
|
45631
|
+
]));
|
|
45632
|
+
}
|
|
45633
|
+
function viewHolding(views, box) {
|
|
45634
|
+
if (!box)
|
|
45635
|
+
return void 0;
|
|
45636
|
+
return views.find(({ box: view }) => box.x >= view.x && box.y >= view.y && box.x < view.x + view.width && box.y < view.y + view.height)?.name;
|
|
45637
|
+
}
|
|
45030
45638
|
async function readLibrary(options) {
|
|
45031
|
-
const { rest, fileKey:
|
|
45639
|
+
const { rest, fileKey: fileKey3, part } = options;
|
|
45640
|
+
const branches = options.branches ?? [];
|
|
45641
|
+
const multiBranch = branches.length > 1;
|
|
45642
|
+
const exported = new Map((part.components ?? []).map((component2) => [component2.id, component2.frame]));
|
|
45032
45643
|
const listed = part.components ? {
|
|
45033
45644
|
sets: part.components.filter((component2) => component2.set).map(asPublished),
|
|
45034
45645
|
components: part.components.filter((component2) => !component2.set).map(asPublished)
|
|
45035
|
-
} : await rest.published(
|
|
45646
|
+
} : await rest.published(fileKey3);
|
|
45036
45647
|
const published = [
|
|
45037
45648
|
...listed.sets,
|
|
45038
45649
|
...listed.components.filter((component2) => !component2.containing_frame?.containingComponentSet)
|
|
45039
45650
|
].filter((meta3) => !DOCUMENTATION_PREFIXES.some((prefix) => meta3.name.startsWith(prefix)));
|
|
45040
|
-
const file2 = await rest.file(
|
|
45041
|
-
const
|
|
45651
|
+
const file2 = await rest.file(fileKey3, multiBranch ? 2 : 1);
|
|
45652
|
+
const views = multiBranch ? viewsByPage(file2.document) : /* @__PURE__ */ new Map();
|
|
45653
|
+
const response = published.length > 0 ? await rest.nodes(fileKey3, published.map((meta3) => meta3.node_id)) : { version: file2.version, nodes: {} };
|
|
45042
45654
|
const components = [];
|
|
45655
|
+
const localComponents = /* @__PURE__ */ new Set();
|
|
45656
|
+
for (const entry of Object.values(response.nodes))
|
|
45657
|
+
for (const meta3 of Object.values(entry?.components ?? {}))
|
|
45658
|
+
if (meta3.remote === false)
|
|
45659
|
+
localComponents.add(meta3.key);
|
|
45043
45660
|
for (const meta3 of published) {
|
|
45044
45661
|
const entry = response.nodes[meta3.node_id];
|
|
45045
45662
|
if (!entry)
|
|
45046
45663
|
continue;
|
|
45047
45664
|
const variantNodes = entry.document.type === "COMPONENT_SET" ? (entry.document.children ?? []).filter((child) => child.type === "COMPONENT") : [entry.document];
|
|
45665
|
+
const view = exported.has(meta3.node_id) ? exported.get(meta3.node_id) : viewHolding(views.get(meta3.containing_frame?.pageName ?? "") ?? [], entry.document.absoluteBoundingBox);
|
|
45666
|
+
const branch = multiBranch ? viewBranch(view, branches) : void 0;
|
|
45048
45667
|
components.push({
|
|
45049
45668
|
name: meta3.name,
|
|
45050
45669
|
key: meta3.key,
|
|
45051
45670
|
page: (meta3.containing_frame?.pageName ?? "").replace(/^\W+\s*/, ""),
|
|
45671
|
+
...branch ? { branch } : {},
|
|
45052
45672
|
...descriptionMap(meta3.description),
|
|
45053
45673
|
variants: variantNodes.map((variant) => ({
|
|
45054
45674
|
key: entry.components[variant.id]?.key ?? "",
|
|
@@ -45062,11 +45682,16 @@ async function readLibrary(options) {
|
|
|
45062
45682
|
});
|
|
45063
45683
|
}
|
|
45064
45684
|
return {
|
|
45065
|
-
source:
|
|
45685
|
+
source: fileKey3,
|
|
45066
45686
|
version: file2.version,
|
|
45067
45687
|
exportedAt: part.exportedAt,
|
|
45068
45688
|
components,
|
|
45069
45689
|
textStyles: part.textStyles,
|
|
45690
|
+
...part.variableKeys ? {
|
|
45691
|
+
variableKeys: part.variableKeys,
|
|
45692
|
+
effectStyles: part.effectStyles ?? [],
|
|
45693
|
+
localComponents: [...localComponents].sort()
|
|
45694
|
+
} : {},
|
|
45070
45695
|
tokens: part.tokens.map((token) => ({
|
|
45071
45696
|
combo: token.combo,
|
|
45072
45697
|
values: Object.fromEntries(Object.entries(token.values).map(([name, value]) => [
|
|
@@ -45076,18 +45701,57 @@ async function readLibrary(options) {
|
|
|
45076
45701
|
}))
|
|
45077
45702
|
};
|
|
45078
45703
|
}
|
|
45704
|
+
async function readKit(options) {
|
|
45705
|
+
const components = await options.rest.components(options.key);
|
|
45706
|
+
return {
|
|
45707
|
+
key: options.key,
|
|
45708
|
+
family: options.family,
|
|
45709
|
+
components: components.map((component2) => ({ key: component2.key, name: component2.name }))
|
|
45710
|
+
};
|
|
45711
|
+
}
|
|
45079
45712
|
|
|
45080
45713
|
// packages/zaku/dist/lib/handlers/save-library.js
|
|
45714
|
+
function librarySaveTarget(config2, key) {
|
|
45715
|
+
const graph = designGraph(config2);
|
|
45716
|
+
const keys = [...graph.libraries, ...graph.kits].map((file2) => file2.key);
|
|
45717
|
+
if (keys.length === 0) {
|
|
45718
|
+
const byRole2 = config2.figma.libraries !== void 0 || config2.figma.kits !== void 0;
|
|
45719
|
+
throw new FigmaFileKeyMissing(byRole2 ? "figma.libraries" : "figma.library");
|
|
45720
|
+
}
|
|
45721
|
+
const library = key === void 0 ? graph.libraries.length === 1 ? graph.libraries[0] : void 0 : void 0;
|
|
45722
|
+
if (library)
|
|
45723
|
+
return { kind: "library", library, legacy: graph.legacy };
|
|
45724
|
+
if (key === void 0)
|
|
45725
|
+
throw new LibraryKeyMissing(keys);
|
|
45726
|
+
const named = graph.libraries.find((candidate) => candidate.key === key);
|
|
45727
|
+
if (named)
|
|
45728
|
+
return { kind: "library", library: named, legacy: graph.legacy };
|
|
45729
|
+
const kit = graph.kits.find((candidate) => candidate.key === key);
|
|
45730
|
+
if (kit)
|
|
45731
|
+
return { kind: "kit", kit };
|
|
45732
|
+
throw new LibraryKeyMissing(keys, key);
|
|
45733
|
+
}
|
|
45081
45734
|
async function saveLibrary(options) {
|
|
45082
45735
|
const paths = designPaths(options.root);
|
|
45083
45736
|
const config2 = await readDesignFile(paths.config, zakuConfigSchema);
|
|
45084
|
-
const
|
|
45085
|
-
if (
|
|
45086
|
-
|
|
45087
|
-
|
|
45088
|
-
|
|
45089
|
-
|
|
45090
|
-
|
|
45737
|
+
const target = librarySaveTarget(config2, options.key);
|
|
45738
|
+
if (target.kind === "kit") {
|
|
45739
|
+
const at2 = librarySnapshotDir(paths, target.kit.key);
|
|
45740
|
+
const kit = await readKit({ rest: options.rest, key: target.kit.key, family: target.kit.family });
|
|
45741
|
+
await writeKitSnapshot(at2, kit);
|
|
45742
|
+
return { kind: "kit", dir: relative2(paths.root, at2.library), kit };
|
|
45743
|
+
}
|
|
45744
|
+
if (!options.part)
|
|
45745
|
+
throw new TypeError(`saving library ${target.library.key} needs the variables export`);
|
|
45746
|
+
const { key, branches } = target.library;
|
|
45747
|
+
const at = librarySnapshotDir(paths, target.legacy ? null : key);
|
|
45748
|
+
const snapshot = librarySnapshotSchema.parse(await readLibrary({ rest: options.rest, fileKey: key, part: options.part, branches }));
|
|
45749
|
+
return {
|
|
45750
|
+
kind: "library",
|
|
45751
|
+
dir: relative2(paths.root, at.library),
|
|
45752
|
+
snapshot,
|
|
45753
|
+
...await writeLibrarySnapshot(at, snapshot)
|
|
45754
|
+
};
|
|
45091
45755
|
}
|
|
45092
45756
|
var SaveLibraryHandler = class SaveLibraryHandler2 {
|
|
45093
45757
|
rest;
|
|
@@ -45096,7 +45760,12 @@ var SaveLibraryHandler = class SaveLibraryHandler2 {
|
|
|
45096
45760
|
this.rest = rest;
|
|
45097
45761
|
}
|
|
45098
45762
|
handle(command) {
|
|
45099
|
-
return saveLibrary({
|
|
45763
|
+
return saveLibrary({
|
|
45764
|
+
root: command.root,
|
|
45765
|
+
rest: this.rest,
|
|
45766
|
+
...command.key !== void 0 ? { key: command.key } : {},
|
|
45767
|
+
...command.part !== void 0 ? { part: command.part } : {}
|
|
45768
|
+
});
|
|
45100
45769
|
}
|
|
45101
45770
|
};
|
|
45102
45771
|
SaveLibraryHandler = __decorate2([
|
|
@@ -45106,9 +45775,10 @@ SaveLibraryHandler = __decorate2([
|
|
|
45106
45775
|
|
|
45107
45776
|
// packages/zaku/dist/lib/handlers/write-outline.js
|
|
45108
45777
|
var import_tsyringe4 = __toESM(require_cjs(), 1);
|
|
45778
|
+
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
45109
45779
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
45110
|
-
import { mkdir, rm, writeFile as writeFile3 } from "node:fs/promises";
|
|
45111
|
-
import { dirname as dirname2 } from "node:path";
|
|
45780
|
+
import { mkdir as mkdir2, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
|
|
45781
|
+
import { dirname as dirname2, join as join6 } from "node:path";
|
|
45112
45782
|
|
|
45113
45783
|
// packages/zaku/dist/lib/domain/documentation-measures.js
|
|
45114
45784
|
var COVER = {
|
|
@@ -45496,8 +46166,8 @@ var DOCUMENTATION_PARTS = [
|
|
|
45496
46166
|
|
|
45497
46167
|
// packages/zaku/dist/lib/repositories/feature-maps.js
|
|
45498
46168
|
import { createHash } from "node:crypto";
|
|
45499
|
-
import { readdir, readFile as
|
|
45500
|
-
import { basename, join as
|
|
46169
|
+
import { readdir as readdir2, readFile as readFile3 } from "node:fs/promises";
|
|
46170
|
+
import { basename, join as join4 } from "node:path";
|
|
45501
46171
|
|
|
45502
46172
|
// packages/zaku/dist/lib/domain/feature-map.js
|
|
45503
46173
|
var slug = external_exports.string().regex(/^[a-z][a-z0-9-]*$/, "lowercase letters, digits and dashes, starting with a letter");
|
|
@@ -45565,7 +46235,7 @@ function digestOf(text) {
|
|
|
45565
46235
|
async function loadMaps(dir) {
|
|
45566
46236
|
let names;
|
|
45567
46237
|
try {
|
|
45568
|
-
names = (await
|
|
46238
|
+
names = (await readdir2(dir)).filter((name) => name.endsWith(".yaml")).sort();
|
|
45569
46239
|
} catch (error62) {
|
|
45570
46240
|
if (error62.code === "ENOENT")
|
|
45571
46241
|
return { maps: [], errors: [] };
|
|
@@ -45574,8 +46244,8 @@ async function loadMaps(dir) {
|
|
|
45574
46244
|
const maps = [];
|
|
45575
46245
|
const errors = [];
|
|
45576
46246
|
for (const name of names) {
|
|
45577
|
-
const path2 =
|
|
45578
|
-
const text = await
|
|
46247
|
+
const path2 = join4(dir, name);
|
|
46248
|
+
const text = await readFile3(path2, "utf8");
|
|
45579
46249
|
try {
|
|
45580
46250
|
const map2 = parseDesignFile(path2, text, featureMapSchema);
|
|
45581
46251
|
if (`${map2.feature}.yaml` !== basename(path2)) {
|
|
@@ -45616,6 +46286,9 @@ function indexTitles(maps) {
|
|
|
45616
46286
|
return { titles, duplicates };
|
|
45617
46287
|
}
|
|
45618
46288
|
|
|
46289
|
+
// packages/zaku/dist/lib/adapters/figma-rest-outline.js
|
|
46290
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
46291
|
+
|
|
45619
46292
|
// packages/zaku/dist/lib/domain/layer-names.js
|
|
45620
46293
|
var DEFAULT_NAMES = {
|
|
45621
46294
|
FRAME: ["Frame"],
|
|
@@ -45684,7 +46357,7 @@ function outlineFrame(frame, where, ctx) {
|
|
|
45684
46357
|
const images2 = [];
|
|
45685
46358
|
const defaultNames = [];
|
|
45686
46359
|
const links = [];
|
|
45687
|
-
const
|
|
46360
|
+
const relative3 = (node2) => {
|
|
45688
46361
|
const box = node2.absoluteBoundingBox;
|
|
45689
46362
|
return box ? { x: box.x - origin.x, y: box.y - origin.y, width: box.width, height: box.height } : null;
|
|
45690
46363
|
};
|
|
@@ -45713,7 +46386,7 @@ function outlineFrame(frame, where, ctx) {
|
|
|
45713
46386
|
componentKey: ctx.components[child.componentId ?? ""]?.key ?? "",
|
|
45714
46387
|
component: component2,
|
|
45715
46388
|
interactive: ctx.interactive.has(component2),
|
|
45716
|
-
bounds:
|
|
46389
|
+
bounds: relative3(child)
|
|
45717
46390
|
});
|
|
45718
46391
|
} else if (child.type === "TEXT") {
|
|
45719
46392
|
instance.texts.push({
|
|
@@ -45754,7 +46427,7 @@ function outlineFrame(frame, where, ctx) {
|
|
|
45754
46427
|
texts: [],
|
|
45755
46428
|
interactive: ctx.interactive.has(component2),
|
|
45756
46429
|
local: meta3?.remote === false,
|
|
45757
|
-
bounds:
|
|
46430
|
+
bounds: relative3(node2),
|
|
45758
46431
|
sizing: {
|
|
45759
46432
|
horizontal: node2.layoutSizingHorizontal ?? "FIXED",
|
|
45760
46433
|
vertical: node2.layoutSizingVertical ?? "FIXED"
|
|
@@ -45803,6 +46476,17 @@ function outlineFrame(frame, where, ctx) {
|
|
|
45803
46476
|
links.push(...linksOf(frame));
|
|
45804
46477
|
for (const child of shown(frame))
|
|
45805
46478
|
walk(child);
|
|
46479
|
+
const drawn = {
|
|
46480
|
+
size: [origin.width, origin.height],
|
|
46481
|
+
instances: instances.map((instance) => [
|
|
46482
|
+
instance.componentKey,
|
|
46483
|
+
instance.variant,
|
|
46484
|
+
instance.properties,
|
|
46485
|
+
instance.texts.map((text) => text.characters),
|
|
46486
|
+
instance.bounds
|
|
46487
|
+
]),
|
|
46488
|
+
texts: texts.map((text) => text.characters)
|
|
46489
|
+
};
|
|
45806
46490
|
return {
|
|
45807
46491
|
nodeId: frame.id,
|
|
45808
46492
|
name: frame.name,
|
|
@@ -45816,13 +46500,14 @@ function outlineFrame(frame, where, ctx) {
|
|
|
45816
46500
|
raw,
|
|
45817
46501
|
images: images2,
|
|
45818
46502
|
defaultNames,
|
|
45819
|
-
links
|
|
46503
|
+
links,
|
|
46504
|
+
digest: createHash2("sha256").update(JSON.stringify(drawn)).digest("hex").slice(0, 16)
|
|
45820
46505
|
};
|
|
45821
46506
|
}
|
|
45822
46507
|
|
|
45823
46508
|
// packages/zaku/dist/lib/repositories/outlines.js
|
|
45824
|
-
import { readdir as
|
|
45825
|
-
import { join as
|
|
46509
|
+
import { readdir as readdir3 } from "node:fs/promises";
|
|
46510
|
+
import { join as join5 } from "node:path";
|
|
45826
46511
|
|
|
45827
46512
|
// packages/zaku/dist/lib/domain/outline.js
|
|
45828
46513
|
var boundsSchema = external_exports.object({ x: external_exports.number(), y: external_exports.number(), width: external_exports.number(), height: external_exports.number() }).strict();
|
|
@@ -45882,43 +46567,103 @@ var frameOutlineSchema = external_exports.object({
|
|
|
45882
46567
|
raw: external_exports.array(rawOutlineSchema),
|
|
45883
46568
|
images: external_exports.array(imageOutlineSchema),
|
|
45884
46569
|
defaultNames: external_exports.array(external_exports.object({ nodeId: external_exports.string(), name: external_exports.string() }).strict()),
|
|
45885
|
-
links: external_exports.array(linkOutlineSchema)
|
|
46570
|
+
links: external_exports.array(linkOutlineSchema),
|
|
46571
|
+
/** In a product file of one page per screen: the page the frame is on, and the product file it is in. */
|
|
46572
|
+
page: external_exports.string().optional(),
|
|
46573
|
+
source: external_exports.string().optional(),
|
|
46574
|
+
/** What the frame draws, without its node ids, so a copy and its source digest alike. */
|
|
46575
|
+
digest: external_exports.string().optional()
|
|
46576
|
+
}).strict();
|
|
46577
|
+
var flowOutlineSchema = external_exports.object({
|
|
46578
|
+
/** The Figma file key the page is in. */
|
|
46579
|
+
source: external_exports.string(),
|
|
46580
|
+
page: external_exports.string(),
|
|
46581
|
+
fileVersion: external_exports.string(),
|
|
46582
|
+
frames: external_exports.array(external_exports.object({
|
|
46583
|
+
nodeId: external_exports.string(),
|
|
46584
|
+
name: external_exports.string(),
|
|
46585
|
+
screen: external_exports.string().nullable(),
|
|
46586
|
+
target: external_exports.string(),
|
|
46587
|
+
state: external_exports.string(),
|
|
46588
|
+
start: external_exports.boolean(),
|
|
46589
|
+
links: external_exports.array(linkOutlineSchema),
|
|
46590
|
+
digest: external_exports.string()
|
|
46591
|
+
}).strict())
|
|
45886
46592
|
}).strict();
|
|
45887
|
-
var
|
|
46593
|
+
var LEGACY_LIBRARY_VERSION = "figma.library";
|
|
46594
|
+
function legacyVersion(value) {
|
|
46595
|
+
if (value === null || typeof value !== "object" || !("libraryVersion" in value))
|
|
46596
|
+
return value;
|
|
46597
|
+
const { libraryVersion, ...rest } = value;
|
|
46598
|
+
return {
|
|
46599
|
+
...rest,
|
|
46600
|
+
libraryVersions: typeof libraryVersion === "string" ? { [LEGACY_LIBRARY_VERSION]: libraryVersion } : {}
|
|
46601
|
+
};
|
|
46602
|
+
}
|
|
46603
|
+
var screenOutlineSchema = external_exports.preprocess(legacyVersion, external_exports.object({
|
|
45888
46604
|
feature: external_exports.string(),
|
|
45889
46605
|
screen: external_exports.string(),
|
|
45890
46606
|
/** The Figma file key the frames were read from. */
|
|
45891
46607
|
source: external_exports.string(),
|
|
45892
46608
|
fileVersion: external_exports.string(),
|
|
45893
46609
|
mapDigest: external_exports.string(),
|
|
45894
|
-
|
|
46610
|
+
/** The version of each library snapshot the frames were read against, by key. */
|
|
46611
|
+
libraryVersions: external_exports.record(external_exports.string(), external_exports.string()),
|
|
46612
|
+
/** The version of every product file zaku.yaml lists, when it lists them by platform. */
|
|
46613
|
+
fileVersions: external_exports.record(external_exports.string(), external_exports.string()).optional(),
|
|
45895
46614
|
frames: external_exports.array(frameOutlineSchema)
|
|
45896
|
-
}).strict();
|
|
46615
|
+
}).strict());
|
|
45897
46616
|
var unmappedSchema = external_exports.object({
|
|
45898
46617
|
fileVersion: external_exports.string(),
|
|
45899
|
-
frames: external_exports.array(external_exports.object({ nodeId: external_exports.string(), name: external_exports.string() }).strict())
|
|
46618
|
+
frames: external_exports.array(external_exports.object({ nodeId: external_exports.string(), name: external_exports.string() }).strict()),
|
|
46619
|
+
/** A component drawn on a product page, which belongs in a Components library. */
|
|
46620
|
+
components: external_exports.array(external_exports.object({ nodeId: external_exports.string(), name: external_exports.string(), page: external_exports.string(), source: external_exports.string() }).strict()).optional()
|
|
45900
46621
|
}).strict();
|
|
45901
46622
|
|
|
45902
46623
|
// packages/zaku/dist/lib/repositories/outlines.js
|
|
46624
|
+
var FLOWS_DIR = "flows";
|
|
46625
|
+
function flowOutlinePath(dir, source, page) {
|
|
46626
|
+
const slug2 = page.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "page";
|
|
46627
|
+
return join5(dir, FLOWS_DIR, source, `${slug2}.yaml`);
|
|
46628
|
+
}
|
|
45903
46629
|
function outlinePath(dir, feature, screen) {
|
|
45904
|
-
return
|
|
46630
|
+
return join5(dir, feature, `${screen}.yaml`);
|
|
45905
46631
|
}
|
|
45906
46632
|
async function loadOutlines(dir) {
|
|
45907
46633
|
const outlines = [];
|
|
46634
|
+
const flows = [];
|
|
45908
46635
|
const errors = [];
|
|
45909
46636
|
let features;
|
|
45910
46637
|
try {
|
|
45911
|
-
features = (await
|
|
46638
|
+
features = (await readdir3(dir, { withFileTypes: true })).filter((entry) => entry.isDirectory() && entry.name !== FLOWS_DIR).map((entry) => entry.name).sort();
|
|
45912
46639
|
} catch (error62) {
|
|
45913
46640
|
if (error62.code === "ENOENT")
|
|
45914
|
-
return { outlines, unmapped: null, errors };
|
|
46641
|
+
return { outlines, flows, unmapped: null, errors };
|
|
45915
46642
|
throw error62;
|
|
45916
46643
|
}
|
|
45917
46644
|
for (const feature of features) {
|
|
45918
|
-
const files2 = (await
|
|
46645
|
+
const files2 = (await readdir3(join5(dir, feature))).filter((name) => name.endsWith(".yaml")).sort();
|
|
46646
|
+
for (const file2 of files2) {
|
|
46647
|
+
try {
|
|
46648
|
+
outlines.push(await readDesignFile(join5(dir, feature, file2), screenOutlineSchema));
|
|
46649
|
+
} catch (error62) {
|
|
46650
|
+
if (error62 instanceof DesignFileInvalid)
|
|
46651
|
+
errors.push(error62);
|
|
46652
|
+
else
|
|
46653
|
+
throw error62;
|
|
46654
|
+
}
|
|
46655
|
+
}
|
|
46656
|
+
}
|
|
46657
|
+
const sources = await readdir3(join5(dir, FLOWS_DIR)).catch((error62) => {
|
|
46658
|
+
if (error62.code === "ENOENT")
|
|
46659
|
+
return [];
|
|
46660
|
+
throw error62;
|
|
46661
|
+
});
|
|
46662
|
+
for (const source of sources.sort()) {
|
|
46663
|
+
const files2 = (await readdir3(join5(dir, FLOWS_DIR, source))).filter((name) => name.endsWith(".yaml")).sort();
|
|
45919
46664
|
for (const file2 of files2) {
|
|
45920
46665
|
try {
|
|
45921
|
-
|
|
46666
|
+
flows.push(await readDesignFile(join5(dir, FLOWS_DIR, source, file2), flowOutlineSchema));
|
|
45922
46667
|
} catch (error62) {
|
|
45923
46668
|
if (error62 instanceof DesignFileInvalid)
|
|
45924
46669
|
errors.push(error62);
|
|
@@ -45929,14 +46674,14 @@ async function loadOutlines(dir) {
|
|
|
45929
46674
|
}
|
|
45930
46675
|
let unmapped = null;
|
|
45931
46676
|
try {
|
|
45932
|
-
unmapped = await readOptionalDesignFile(
|
|
46677
|
+
unmapped = await readOptionalDesignFile(join5(dir, "unmapped.yaml"), unmappedSchema);
|
|
45933
46678
|
} catch (error62) {
|
|
45934
46679
|
if (error62 instanceof DesignFileInvalid)
|
|
45935
46680
|
errors.push(error62);
|
|
45936
46681
|
else
|
|
45937
46682
|
throw error62;
|
|
45938
46683
|
}
|
|
45939
|
-
return { outlines, unmapped, errors };
|
|
46684
|
+
return { outlines, flows, unmapped, errors };
|
|
45940
46685
|
}
|
|
45941
46686
|
|
|
45942
46687
|
// packages/zaku/dist/lib/handlers/write-outline.js
|
|
@@ -45973,108 +46718,215 @@ function resolveFrame(frame, parsed, maps) {
|
|
|
45973
46718
|
return candidates.find((ref) => ref.feature === pageFeature);
|
|
45974
46719
|
return candidates.length === 1 ? candidates[0] : void 0;
|
|
45975
46720
|
}
|
|
46721
|
+
function resolveTitle(parsed, maps) {
|
|
46722
|
+
const candidates = [...indexScreens(maps).values()].filter((ref) => ref.screen.title === parsed.title);
|
|
46723
|
+
return candidates.length === 1 ? candidates[0] : void 0;
|
|
46724
|
+
}
|
|
45976
46725
|
function looksLikeScreenFrame(name) {
|
|
45977
46726
|
return name.includes("/");
|
|
45978
46727
|
}
|
|
45979
|
-
function holdsScreens(page) {
|
|
46728
|
+
function holdsScreens(page, prototypes = /* @__PURE__ */ new Set()) {
|
|
45980
46729
|
if (page === COVER.page || page === DOCUMENTATION_COMPONENTS_PAGE || page === DIRECTIONS_PAGE)
|
|
45981
46730
|
return false;
|
|
46731
|
+
if (prototypes.has(page))
|
|
46732
|
+
return false;
|
|
45982
46733
|
return !page.startsWith("\u2756 ") && !page.includes(" / ") && !/^-+$/.test(page);
|
|
45983
46734
|
}
|
|
46735
|
+
function listComponents(document, source) {
|
|
46736
|
+
const out = [];
|
|
46737
|
+
for (const page of document.children ?? []) {
|
|
46738
|
+
if (page.type !== "CANVAS" || !holdsScreens(page.name))
|
|
46739
|
+
continue;
|
|
46740
|
+
const walk = (node2) => {
|
|
46741
|
+
for (const child of node2.children ?? []) {
|
|
46742
|
+
if (child.type === "COMPONENT" || child.type === "COMPONENT_SET")
|
|
46743
|
+
out.push({ nodeId: child.id, name: child.name, page: page.name, source });
|
|
46744
|
+
else if (child.type === "SECTION")
|
|
46745
|
+
walk(child);
|
|
46746
|
+
}
|
|
46747
|
+
};
|
|
46748
|
+
walk(page);
|
|
46749
|
+
}
|
|
46750
|
+
return out;
|
|
46751
|
+
}
|
|
46752
|
+
function productFiles(config2) {
|
|
46753
|
+
const graph = designGraph(config2);
|
|
46754
|
+
if (graph.legacy)
|
|
46755
|
+
return config2.figma.product === void 0 ? [] : [{ key: config2.figma.product, targets: config2.targets }];
|
|
46756
|
+
return graph.products.map((product) => ({
|
|
46757
|
+
key: product.key,
|
|
46758
|
+
targets: config2.targets.filter((target) => graph.platformOf(target) === product.platform)
|
|
46759
|
+
}));
|
|
46760
|
+
}
|
|
45984
46761
|
async function runOutline(options) {
|
|
45985
46762
|
const paths = designPaths(options.root);
|
|
45986
46763
|
const config2 = await readDesignFile(paths.config, zakuConfigSchema);
|
|
45987
|
-
const
|
|
45988
|
-
|
|
45989
|
-
|
|
46764
|
+
const { libraries: listed, kits, products: byPlatform, prototypes: flows } = config2.figma;
|
|
46765
|
+
const legacy = [listed, kits, byPlatform, flows].every((files2) => files2 === void 0);
|
|
46766
|
+
const products = productFiles(config2);
|
|
46767
|
+
if (products.length === 0)
|
|
46768
|
+
throw new FigmaFileKeyMissing(legacy ? "figma.product" : "figma.products");
|
|
45990
46769
|
const { maps, errors } = await loadMaps(paths.maps);
|
|
45991
46770
|
if (errors[0])
|
|
45992
46771
|
throw errors[0];
|
|
45993
46772
|
const digests = new Map(maps.map((loaded) => [loaded.map.feature, loaded.digest]));
|
|
45994
|
-
const
|
|
46773
|
+
const { libraries } = await readDesignSnapshots(paths, config2);
|
|
46774
|
+
const libraryVersions = Object.fromEntries(Object.entries(libraries).map(([key, library]) => [key, library.version]));
|
|
45995
46775
|
const existing = await loadOutlines(paths.outline);
|
|
45996
|
-
const
|
|
45997
|
-
const
|
|
46776
|
+
const prototypes = new Set(legacy ? config2.targets.map((target) => `${target.name} prototype`) : []);
|
|
46777
|
+
const versions = {};
|
|
46778
|
+
const flowPages = /* @__PURE__ */ new Map();
|
|
46779
|
+
const flowFrame = (source, frame, targets) => {
|
|
46780
|
+
const parsed = parseFrameName(frame.name, targets);
|
|
46781
|
+
if (!parsed)
|
|
46782
|
+
return;
|
|
46783
|
+
const key = `${source}
|
|
46784
|
+
${frame.page}`;
|
|
46785
|
+
const page = flowPages.get(key) ?? { source, page: frame.page, frames: [] };
|
|
46786
|
+
page.frames.push({ frame, parsed });
|
|
46787
|
+
flowPages.set(key, page);
|
|
46788
|
+
};
|
|
45998
46789
|
const resolved = /* @__PURE__ */ new Map();
|
|
45999
|
-
const unmapped = { fileVersion:
|
|
46000
|
-
|
|
46001
|
-
|
|
46002
|
-
|
|
46003
|
-
|
|
46790
|
+
const unmapped = { fileVersion: "", frames: [] };
|
|
46791
|
+
const components = [];
|
|
46792
|
+
for (const product of products) {
|
|
46793
|
+
const file2 = await options.rest.file(product.key, INDEX_DEPTH);
|
|
46794
|
+
versions[product.key] = file2.version;
|
|
46795
|
+
const listed2 = listFrames(file2.document);
|
|
46796
|
+
for (const frame of listed2.filter((candidate) => prototypes.has(candidate.page)))
|
|
46797
|
+
flowFrame(product.key, frame, product.targets);
|
|
46798
|
+
for (const frame of listed2.filter((candidate) => holdsScreens(candidate.page, prototypes))) {
|
|
46799
|
+
const parsed = parseFrameName(frame.name, product.targets);
|
|
46800
|
+
if (!parsed) {
|
|
46801
|
+
if (looksLikeScreenFrame(frame.name))
|
|
46802
|
+
unmapped.frames.push({ nodeId: frame.id, name: frame.name });
|
|
46803
|
+
continue;
|
|
46804
|
+
}
|
|
46805
|
+
const ref = legacy ? resolveFrame(frame, parsed, maps) : resolveTitle(parsed, maps);
|
|
46806
|
+
if (ref)
|
|
46807
|
+
resolved.set(frame.id, { frame, parsed, ref, source: product.key });
|
|
46808
|
+
else
|
|
46004
46809
|
unmapped.frames.push({ nodeId: frame.id, name: frame.name });
|
|
46005
|
-
continue;
|
|
46006
46810
|
}
|
|
46007
|
-
|
|
46008
|
-
|
|
46009
|
-
|
|
46010
|
-
|
|
46011
|
-
|
|
46811
|
+
if (!legacy)
|
|
46812
|
+
components.push(...listComponents(file2.document, product.key));
|
|
46813
|
+
}
|
|
46814
|
+
const graph = designGraph(config2);
|
|
46815
|
+
for (const file2 of legacy ? [] : graph.prototypes) {
|
|
46816
|
+
const read = await options.rest.file(file2.key, INDEX_DEPTH);
|
|
46817
|
+
versions[file2.key] = read.version;
|
|
46818
|
+
const targets = config2.targets.filter((target) => graph.platformOf(target) === file2.platform);
|
|
46819
|
+
for (const frame of listFrames(read.document).filter((candidate) => holdsScreens(candidate.page)))
|
|
46820
|
+
flowFrame(file2.key, frame, targets);
|
|
46012
46821
|
}
|
|
46822
|
+
unmapped.fileVersion = Object.values(versions).join(",");
|
|
46823
|
+
if (!legacy)
|
|
46824
|
+
unmapped.components = components;
|
|
46013
46825
|
const outlined = new Set(existing.outlines.flatMap((outline) => outline.frames.map((frame) => frame.nodeId)));
|
|
46014
46826
|
const drawnScreens = new Set([...resolved.values()].map(({ ref }) => `${ref.feature}/${ref.id}`));
|
|
46015
|
-
const current = existing.outlines.every((outline) => outline.fileVersion ===
|
|
46827
|
+
const current = existing.outlines.every((outline) => (legacy ? outline.fileVersion === versions[outline.source] : isDeepStrictEqual2(outline.fileVersions, versions)) && outline.mapDigest === digests.get(outline.feature) && isDeepStrictEqual2(outline.libraryVersions, libraryVersions)) && [...resolved.keys()].every((id2) => outlined.has(id2)) && existing.flows.length === flowPages.size && existing.flows.every((flow) => flow.fileVersion === versions[flow.source]) && existing.outlines.every((outline) => drawnScreens.has(`${outline.feature}/${outline.screen}`));
|
|
46016
46828
|
if (options.frames === null && existing.outlines.length > 0 && current) {
|
|
46017
46829
|
return { skipped: true, read: 0, written: [], unmapped: unmapped.frames.length };
|
|
46018
46830
|
}
|
|
46019
46831
|
const ids = options.frames ?? [...resolved.keys()];
|
|
46020
|
-
const response = ids.length > 0 ? await options.rest.nodes(fileKey2, ids) : { version: file2.version, nodes: {} };
|
|
46021
46832
|
const byScreen = /* @__PURE__ */ new Map();
|
|
46022
46833
|
if (options.frames !== null) {
|
|
46023
46834
|
for (const outline of existing.outlines)
|
|
46024
46835
|
byScreen.set(`${outline.feature}/${outline.screen}`, outline);
|
|
46025
46836
|
}
|
|
46026
46837
|
const interactive = new Set(config2.interactive);
|
|
46027
|
-
|
|
46028
|
-
|
|
46029
|
-
|
|
46030
|
-
const read = await options.rest.nodes(fileKey2, [...resized]);
|
|
46031
|
-
for (const [id2, entry] of Object.entries(read.nodes)) {
|
|
46032
|
-
const box = entry?.document.absoluteBoundingBox;
|
|
46033
|
-
if (box)
|
|
46034
|
-
sizes.set(id2, { width: box.width, height: box.height });
|
|
46035
|
-
}
|
|
46036
|
-
}
|
|
46037
|
-
for (const [id2, entry] of Object.entries(response.nodes)) {
|
|
46038
|
-
const found = resolved.get(id2);
|
|
46039
|
-
if (!entry || !found)
|
|
46838
|
+
for (const product of products) {
|
|
46839
|
+
const own2 = ids.filter((id2) => resolved.has(id2) ? resolved.get(id2)?.source === product.key : product === products[0]);
|
|
46840
|
+
if (own2.length === 0)
|
|
46040
46841
|
continue;
|
|
46041
|
-
const
|
|
46042
|
-
const
|
|
46043
|
-
const
|
|
46044
|
-
|
|
46045
|
-
|
|
46046
|
-
|
|
46047
|
-
|
|
46048
|
-
|
|
46049
|
-
|
|
46050
|
-
|
|
46051
|
-
}
|
|
46052
|
-
const
|
|
46053
|
-
|
|
46054
|
-
|
|
46055
|
-
|
|
46056
|
-
|
|
46057
|
-
|
|
46058
|
-
|
|
46059
|
-
|
|
46060
|
-
|
|
46061
|
-
|
|
46062
|
-
|
|
46842
|
+
const response = await options.rest.nodes(product.key, own2);
|
|
46843
|
+
const resized = new Set(Object.values(response.nodes).flatMap((entry) => entry ? resizedLocalComponents(entry.document, entry.components) : []));
|
|
46844
|
+
const sizes = /* @__PURE__ */ new Map();
|
|
46845
|
+
if (resized.size > 0) {
|
|
46846
|
+
const read = await options.rest.nodes(product.key, [...resized]);
|
|
46847
|
+
for (const [id2, entry] of Object.entries(read.nodes)) {
|
|
46848
|
+
const box = entry?.document.absoluteBoundingBox;
|
|
46849
|
+
if (box)
|
|
46850
|
+
sizes.set(id2, { width: box.width, height: box.height });
|
|
46851
|
+
}
|
|
46852
|
+
}
|
|
46853
|
+
for (const [id2, entry] of Object.entries(response.nodes)) {
|
|
46854
|
+
const found = resolved.get(id2);
|
|
46855
|
+
if (!entry || !found)
|
|
46856
|
+
continue;
|
|
46857
|
+
const { frame: place, parsed, ref } = found;
|
|
46858
|
+
const key = `${ref.feature}/${ref.id}`;
|
|
46859
|
+
const outline = byScreen.get(key) ?? {
|
|
46860
|
+
feature: ref.feature,
|
|
46861
|
+
screen: ref.id,
|
|
46862
|
+
source: product.key,
|
|
46863
|
+
fileVersion: versions[product.key] ?? "",
|
|
46864
|
+
mapDigest: "",
|
|
46865
|
+
libraryVersions: {},
|
|
46866
|
+
frames: []
|
|
46867
|
+
};
|
|
46868
|
+
const frame = outlineFrame(entry.document, {
|
|
46869
|
+
target: parsed.target.id,
|
|
46870
|
+
state: parsed.state,
|
|
46871
|
+
containers: place.containers,
|
|
46872
|
+
start: place.start
|
|
46873
|
+
}, { ...entry, interactive, sizes });
|
|
46874
|
+
if (!legacy)
|
|
46875
|
+
Object.assign(frame, { page: place.page, source: product.key });
|
|
46876
|
+
outline.frames = [...outline.frames.filter((kept) => kept.nodeId !== id2), frame].sort((a, b) => a.name.localeCompare(b.name));
|
|
46877
|
+
outline.mapDigest = digests.get(ref.feature) ?? "";
|
|
46878
|
+
outline.libraryVersions = libraryVersions;
|
|
46879
|
+
if (legacy)
|
|
46880
|
+
outline.fileVersion = versions[product.key] ?? "";
|
|
46881
|
+
else
|
|
46882
|
+
outline.fileVersions = versions;
|
|
46883
|
+
byScreen.set(key, outline);
|
|
46884
|
+
}
|
|
46063
46885
|
}
|
|
46064
46886
|
if (options.frames === null) {
|
|
46887
|
+
await rm2(join6(paths.outline, FLOWS_DIR), { recursive: true, force: true });
|
|
46888
|
+
for (const page of flowPages.values()) {
|
|
46889
|
+
const response = await options.rest.nodes(page.source, page.frames.map(({ frame }) => frame.id));
|
|
46890
|
+
const flow = {
|
|
46891
|
+
source: page.source,
|
|
46892
|
+
page: page.page,
|
|
46893
|
+
fileVersion: versions[page.source] ?? "",
|
|
46894
|
+
frames: []
|
|
46895
|
+
};
|
|
46896
|
+
for (const { frame, parsed } of page.frames) {
|
|
46897
|
+
const entry = response.nodes[frame.id];
|
|
46898
|
+
if (!entry)
|
|
46899
|
+
continue;
|
|
46900
|
+
const read = outlineFrame(entry.document, { target: parsed.target.id, state: parsed.state, containers: frame.containers, start: frame.start }, { ...entry, interactive, sizes: /* @__PURE__ */ new Map() });
|
|
46901
|
+
const ref = resolveTitle(parsed, maps);
|
|
46902
|
+
flow.frames.push({
|
|
46903
|
+
nodeId: frame.id,
|
|
46904
|
+
name: frame.name,
|
|
46905
|
+
screen: ref ? `${ref.feature}/${ref.id}` : null,
|
|
46906
|
+
target: parsed.target.id,
|
|
46907
|
+
state: parsed.state,
|
|
46908
|
+
start: frame.start,
|
|
46909
|
+
links: read.links,
|
|
46910
|
+
digest: read.digest ?? ""
|
|
46911
|
+
});
|
|
46912
|
+
}
|
|
46913
|
+
const path2 = flowOutlinePath(paths.outline, page.source, page.page);
|
|
46914
|
+
await mkdir2(dirname2(path2), { recursive: true });
|
|
46915
|
+
await writeFile3(path2, (0, import_yaml2.stringify)(flow));
|
|
46916
|
+
}
|
|
46065
46917
|
for (const outline of existing.outlines) {
|
|
46066
46918
|
if (!byScreen.has(`${outline.feature}/${outline.screen}`))
|
|
46067
|
-
await
|
|
46919
|
+
await rm2(outlinePath(paths.outline, outline.feature, outline.screen), { force: true });
|
|
46068
46920
|
}
|
|
46069
46921
|
}
|
|
46070
46922
|
const written = [];
|
|
46071
46923
|
for (const outline of byScreen.values()) {
|
|
46072
46924
|
const path2 = outlinePath(paths.outline, outline.feature, outline.screen);
|
|
46073
|
-
await
|
|
46925
|
+
await mkdir2(dirname2(path2), { recursive: true });
|
|
46074
46926
|
await writeFile3(path2, (0, import_yaml2.stringify)(outline));
|
|
46075
46927
|
written.push(path2);
|
|
46076
46928
|
}
|
|
46077
|
-
await
|
|
46929
|
+
await mkdir2(paths.outline, { recursive: true });
|
|
46078
46930
|
await writeFile3(paths.unmapped, (0, import_yaml2.stringify)(unmapped));
|
|
46079
46931
|
return {
|
|
46080
46932
|
skipped: false,
|
|
@@ -46190,14 +47042,14 @@ RecipeRepository = __decorate2([
|
|
|
46190
47042
|
|
|
46191
47043
|
// packages/zaku/dist/lib/repositories/json-schema-files.js
|
|
46192
47044
|
var import_tsyringe10 = __toESM(require_cjs(), 1);
|
|
46193
|
-
import { mkdir as
|
|
46194
|
-
import { join as
|
|
47045
|
+
import { mkdir as mkdir3 } from "node:fs/promises";
|
|
47046
|
+
import { join as join7 } from "node:path";
|
|
46195
47047
|
var JsonSchemaFiles = class JsonSchemaFiles2 {
|
|
46196
47048
|
async write(dir, schemas) {
|
|
46197
|
-
await
|
|
47049
|
+
await mkdir3(dir, { recursive: true });
|
|
46198
47050
|
const written = [];
|
|
46199
47051
|
for (const [name, schema] of Object.entries(schemas)) {
|
|
46200
|
-
const path2 =
|
|
47052
|
+
const path2 = join7(dir, name);
|
|
46201
47053
|
await writeDesignFile(path2, schema);
|
|
46202
47054
|
written.push(path2);
|
|
46203
47055
|
}
|
|
@@ -46210,13 +47062,13 @@ JsonSchemaFiles = __decorate2([
|
|
|
46210
47062
|
|
|
46211
47063
|
// packages/zaku/dist/lib/repositories/source-files.js
|
|
46212
47064
|
var import_tsyringe11 = __toESM(require_cjs(), 1);
|
|
46213
|
-
import { readFile as
|
|
47065
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
46214
47066
|
var SourceFiles = class SourceFiles2 {
|
|
46215
47067
|
readText(path2) {
|
|
46216
|
-
return
|
|
47068
|
+
return readFile4(path2, "utf8");
|
|
46217
47069
|
}
|
|
46218
47070
|
async readJson(path2) {
|
|
46219
|
-
return JSON.parse(await
|
|
47071
|
+
return JSON.parse(await readFile4(path2, "utf8"));
|
|
46220
47072
|
}
|
|
46221
47073
|
};
|
|
46222
47074
|
SourceFiles = __decorate2([
|
|
@@ -46224,11 +47076,11 @@ SourceFiles = __decorate2([
|
|
|
46224
47076
|
], SourceFiles);
|
|
46225
47077
|
|
|
46226
47078
|
// packages/zaku/dist/lib/repositories/budget-ledger.js
|
|
46227
|
-
import { mkdir as
|
|
46228
|
-
import { dirname as dirname3, join as
|
|
47079
|
+
import { mkdir as mkdir4, readFile as readFile5, rename as rename3, writeFile as writeFile4 } from "node:fs/promises";
|
|
47080
|
+
import { dirname as dirname3, join as join8 } from "node:path";
|
|
46229
47081
|
function ledgerPath(env, platform, home) {
|
|
46230
|
-
const cache = env["XDG_CACHE_HOME"] ?? (platform === "darwin" ?
|
|
46231
|
-
return
|
|
47082
|
+
const cache = env["XDG_CACHE_HOME"] ?? (platform === "darwin" ? join8(home, "Library", "Caches") : join8(home, ".cache"));
|
|
47083
|
+
return join8(cache, "zaku", "ledger.json");
|
|
46232
47084
|
}
|
|
46233
47085
|
function today(now) {
|
|
46234
47086
|
return now.toISOString().slice(0, 10);
|
|
@@ -46238,7 +47090,7 @@ function seatAndRun(env) {
|
|
|
46238
47090
|
}
|
|
46239
47091
|
async function readLedger(path2, day) {
|
|
46240
47092
|
try {
|
|
46241
|
-
const parsed = JSON.parse(await
|
|
47093
|
+
const parsed = JSON.parse(await readFile5(path2, "utf8"));
|
|
46242
47094
|
const isCount = (seat) => {
|
|
46243
47095
|
const count = seat;
|
|
46244
47096
|
return typeof count === "object" && count !== null && typeof count.mcp === "number" && typeof count.rest === "number" && typeof count.runs === "object" && count.runs !== null && Object.values(count.runs).every((value) => typeof value === "number");
|
|
@@ -46257,11 +47109,11 @@ async function recordCalls(path2, entry) {
|
|
|
46257
47109
|
if (entry.kind === "mcp")
|
|
46258
47110
|
seat.runs[entry.run] = (seat.runs[entry.run] ?? 0) + entry.count;
|
|
46259
47111
|
ledger.seats[entry.seat] = seat;
|
|
46260
|
-
await
|
|
47112
|
+
await mkdir4(dirname3(path2), { recursive: true });
|
|
46261
47113
|
const temporary = `${path2}.${process.pid}.tmp`;
|
|
46262
47114
|
await writeFile4(temporary, `${JSON.stringify(ledger)}
|
|
46263
47115
|
`);
|
|
46264
|
-
await
|
|
47116
|
+
await rename3(temporary, path2);
|
|
46265
47117
|
return ledger;
|
|
46266
47118
|
}
|
|
46267
47119
|
function mcpAllowance(ledger, seat, run, budget) {
|
|
@@ -46297,6 +47149,30 @@ var pairingSchema = external_exports.object({
|
|
|
46297
47149
|
}).strict();
|
|
46298
47150
|
var pairingsFileSchema = external_exports.object({ pairings: external_exports.array(pairingSchema.extend({ hash: external_exports.string() }).strict()) }).strict();
|
|
46299
47151
|
|
|
47152
|
+
// packages/zaku/dist/lib/domain/print-graph.js
|
|
47153
|
+
function printGraph(config2, snapshots) {
|
|
47154
|
+
const graph = designGraph(config2);
|
|
47155
|
+
const lines = ["targets"];
|
|
47156
|
+
for (const target of config2.targets) {
|
|
47157
|
+
const files2 = [
|
|
47158
|
+
...graph.librariesFor(target).map((library) => `${library.key} ${library.layer}`),
|
|
47159
|
+
...graph.kitsFor(target).map((kit) => `${kit.key} ${kit.family} kit`)
|
|
47160
|
+
];
|
|
47161
|
+
const branch = graph.branchOf(target);
|
|
47162
|
+
lines.push(` ${target.name} (${target.id}, ${branch ? `branch ${branch}` : "no branch"}, ${graph.platformOf(target)}): ${files2.join(", ") || "nothing"}`);
|
|
47163
|
+
}
|
|
47164
|
+
lines.push("files");
|
|
47165
|
+
const extendedBy = (key) => graph.libraries.filter((library) => library.extends.includes(key)).map((library) => library.key).join(", ") || "nothing";
|
|
47166
|
+
const saved = (key, present) => present ? "" : ` (no snapshot; run zaku library save --key ${key})`;
|
|
47167
|
+
for (const library of graph.libraries) {
|
|
47168
|
+
lines.push(` ${library.key} ${library.layer} [${library.branches.join(", ")}]: extends ${library.extends.join(", ") || "nothing"}; extended by ${extendedBy(library.key)}${saved(library.key, snapshots.libraries[library.key] !== void 0)}`);
|
|
47169
|
+
}
|
|
47170
|
+
for (const kit of graph.kits) {
|
|
47171
|
+
lines.push(` ${kit.key} ${kit.family} kit: extended by ${extendedBy(kit.key)}${saved(kit.key, snapshots.kits[kit.key] !== void 0)}`);
|
|
47172
|
+
}
|
|
47173
|
+
return lines;
|
|
47174
|
+
}
|
|
47175
|
+
|
|
46300
47176
|
// packages/zaku/dist/lib/adapters/figma-rest.js
|
|
46301
47177
|
var FigmaRateLimited = class extends Error {
|
|
46302
47178
|
url;
|
|
@@ -46341,26 +47217,30 @@ function createFigmaRest(options) {
|
|
|
46341
47217
|
throw new FigmaRateLimited(url2);
|
|
46342
47218
|
}
|
|
46343
47219
|
const chunks = (ids) => Array.from({ length: Math.ceil(ids.length / BATCH) }, (_, index) => ids.slice(index * BATCH, (index + 1) * BATCH));
|
|
47220
|
+
async function components(fileKey3) {
|
|
47221
|
+
const listed = await call(`${BASE}/files/${fileKey3}/components`);
|
|
47222
|
+
return listed.meta.components;
|
|
47223
|
+
}
|
|
46344
47224
|
return {
|
|
46345
|
-
file: (
|
|
46346
|
-
async nodes(
|
|
47225
|
+
file: (fileKey3, depth) => call(`${BASE}/files/${fileKey3}?depth=${depth}`),
|
|
47226
|
+
async nodes(fileKey3, ids) {
|
|
46347
47227
|
const merged = { version: "", nodes: {} };
|
|
46348
47228
|
for (const chunk of chunks(ids)) {
|
|
46349
|
-
const part = await call(`${BASE}/files/${
|
|
47229
|
+
const part = await call(`${BASE}/files/${fileKey3}/nodes?ids=${encodeURIComponent(chunk.join(","))}`);
|
|
46350
47230
|
merged.version = part.version;
|
|
46351
47231
|
Object.assign(merged.nodes, part.nodes);
|
|
46352
47232
|
}
|
|
46353
47233
|
return merged;
|
|
46354
47234
|
},
|
|
46355
|
-
async published(
|
|
46356
|
-
const sets = await call(`${BASE}/files/${
|
|
46357
|
-
|
|
46358
|
-
return { sets: sets.meta.component_sets, components: components.meta.components };
|
|
47235
|
+
async published(fileKey3) {
|
|
47236
|
+
const sets = await call(`${BASE}/files/${fileKey3}/component_sets`);
|
|
47237
|
+
return { sets: sets.meta.component_sets, components: await components(fileKey3) };
|
|
46359
47238
|
},
|
|
46360
|
-
|
|
47239
|
+
components,
|
|
47240
|
+
async images(fileKey3, ids) {
|
|
46361
47241
|
const merged = {};
|
|
46362
47242
|
for (const chunk of chunks(ids)) {
|
|
46363
|
-
const part = await call(`${BASE}/images/${
|
|
47243
|
+
const part = await call(`${BASE}/images/${fileKey3}?ids=${encodeURIComponent(chunk.join(","))}&format=png&scale=1`);
|
|
46364
47244
|
Object.assign(merged, part.images);
|
|
46365
47245
|
}
|
|
46366
47246
|
return merged;
|
|
@@ -46370,17 +47250,40 @@ function createFigmaRest(options) {
|
|
|
46370
47250
|
|
|
46371
47251
|
// packages/zaku/dist/lib/adapters/figma-variables-script.js
|
|
46372
47252
|
async function exportVariables(figma, options) {
|
|
46373
|
-
const collections = await figma.variables.getLocalVariableCollectionsAsync();
|
|
47253
|
+
const collections = [...await figma.variables.getLocalVariableCollectionsAsync()];
|
|
47254
|
+
if (!collections.some((collection) => collection.name === "semantic")) {
|
|
47255
|
+
const available = await figma.teamLibrary.getAvailableLibraryVariableCollectionsAsync();
|
|
47256
|
+
const bases = [
|
|
47257
|
+
...new Set(available.filter((entry) => entry.name === "semantic").map((entry) => entry.libraryName))
|
|
47258
|
+
];
|
|
47259
|
+
if (bases.length === 0)
|
|
47260
|
+
throw new Error("the file has no semantic collection and no enabled library has one");
|
|
47261
|
+
if (bases.length > 1)
|
|
47262
|
+
throw new Error(`several enabled libraries hold a semantic collection: ${bases.join(", ")}; enable only the one this library extends`);
|
|
47263
|
+
const imported = /* @__PURE__ */ new Map();
|
|
47264
|
+
for (const entry of available.filter((candidate) => candidate.libraryName === bases[0])) {
|
|
47265
|
+
for (const listed of await figma.teamLibrary.getVariablesInLibraryCollectionAsync(entry.key)) {
|
|
47266
|
+
const variable = await figma.variables.importVariableByKeyAsync(listed.key);
|
|
47267
|
+
if (!imported.has(variable.variableCollectionId))
|
|
47268
|
+
imported.set(variable.variableCollectionId, await figma.variables.getVariableCollectionByIdAsync(variable.variableCollectionId));
|
|
47269
|
+
}
|
|
47270
|
+
}
|
|
47271
|
+
collections.push(...[...imported.values()].filter(Boolean));
|
|
47272
|
+
}
|
|
46374
47273
|
const semantic = collections.find((collection) => collection.name === "semantic");
|
|
46375
47274
|
if (!semantic)
|
|
46376
47275
|
throw new Error("the library has no semantic variable collection");
|
|
46377
47276
|
const hex3 = (value) => Math.round(Math.min(1, Math.max(0, value)) * 255).toString(16).padStart(2, "0");
|
|
46378
47277
|
const variables = {};
|
|
47278
|
+
const variableKeys = {};
|
|
46379
47279
|
for (const collection of collections) {
|
|
46380
47280
|
for (const id2 of collection.variableIds) {
|
|
46381
47281
|
const variable = await figma.variables.getVariableByIdAsync(id2);
|
|
46382
|
-
if (variable)
|
|
46383
|
-
|
|
47282
|
+
if (!variable)
|
|
47283
|
+
continue;
|
|
47284
|
+
const short = String(id2).replace(/^VariableID:/, "");
|
|
47285
|
+
variables[short] = variable.name;
|
|
47286
|
+
variableKeys[short] = { key: variable.key, local: variable.remote !== true };
|
|
46384
47287
|
}
|
|
46385
47288
|
}
|
|
46386
47289
|
const holder = figma.createFrame();
|
|
@@ -46402,6 +47305,8 @@ async function exportVariables(figma, options) {
|
|
|
46402
47305
|
const values = {};
|
|
46403
47306
|
for (const id2 of semantic.variableIds) {
|
|
46404
47307
|
const variable = await figma.variables.getVariableByIdAsync(id2);
|
|
47308
|
+
if (!variable)
|
|
47309
|
+
continue;
|
|
46405
47310
|
const resolved = variable.resolveForConsumer(holder).value;
|
|
46406
47311
|
values[variable.name] = typeof resolved === "object" && resolved !== null ? `#${hex3(resolved.r)}${hex3(resolved.g)}${hex3(resolved.b)}${hex3(resolved.a ?? 1)}` : resolved;
|
|
46407
47312
|
}
|
|
@@ -46421,21 +47326,31 @@ async function exportVariables(figma, options) {
|
|
|
46421
47326
|
for (const node2 of page.findAllWithCriteria({ types: ["COMPONENT_SET", "COMPONENT"] })) {
|
|
46422
47327
|
if (node2.type === "COMPONENT" && node2.parent?.type === "COMPONENT_SET")
|
|
46423
47328
|
continue;
|
|
47329
|
+
let view = node2;
|
|
47330
|
+
while (view.parent && view.parent.type !== "PAGE")
|
|
47331
|
+
view = view.parent;
|
|
46424
47332
|
components.push({
|
|
46425
47333
|
id: node2.id,
|
|
46426
47334
|
key: node2.key,
|
|
46427
47335
|
name: node2.name,
|
|
46428
47336
|
page: page.name,
|
|
47337
|
+
...view !== node2 && view.parent ? { frame: view.name } : {},
|
|
46429
47338
|
description: node2.description ?? "",
|
|
46430
47339
|
set: node2.type === "COMPONENT_SET"
|
|
46431
47340
|
});
|
|
46432
47341
|
}
|
|
46433
47342
|
}
|
|
46434
47343
|
}
|
|
47344
|
+
const effectStyles = (await figma.getLocalEffectStylesAsync()).map((style) => ({
|
|
47345
|
+
key: style.key,
|
|
47346
|
+
name: style.name
|
|
47347
|
+
}));
|
|
46435
47348
|
return {
|
|
46436
47349
|
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
46437
47350
|
variables,
|
|
47351
|
+
variableKeys,
|
|
46438
47352
|
textStyles,
|
|
47353
|
+
effectStyles,
|
|
46439
47354
|
tokens,
|
|
46440
47355
|
...options.local ? { components } : {}
|
|
46441
47356
|
};
|
|
@@ -47027,15 +47942,15 @@ async function startPluginBridge(options = {}) {
|
|
|
47027
47942
|
});
|
|
47028
47943
|
});
|
|
47029
47944
|
});
|
|
47030
|
-
function request(
|
|
47945
|
+
function request(fileKey3, message, timeoutMs) {
|
|
47031
47946
|
if (port === null)
|
|
47032
47947
|
return Promise.resolve({
|
|
47033
47948
|
ok: false,
|
|
47034
47949
|
error: `no port from ${ports[0]} to ${ports[ports.length - 1]} was free, so zaku mcp could not listen for the plugin`
|
|
47035
47950
|
});
|
|
47036
|
-
const socket = holderOf(
|
|
47951
|
+
const socket = holderOf(fileKey3);
|
|
47037
47952
|
if (!socket)
|
|
47038
|
-
return Promise.resolve({ ok: false, error: `file ${
|
|
47953
|
+
return Promise.resolve({ ok: false, error: `file ${fileKey3} is not open in Figma with the zaku plugin` });
|
|
47039
47954
|
const id2 = `c${++next}`;
|
|
47040
47955
|
return new Promise((resolve3) => {
|
|
47041
47956
|
const timer = setTimeout(() => settle2(id2, { ok: false, error: `no answer from the zaku panel in ${timeoutMs / 1e3} s; ${PARTIAL}` }), timeoutMs);
|
|
@@ -47045,8 +47960,8 @@ async function startPluginBridge(options = {}) {
|
|
|
47045
47960
|
}
|
|
47046
47961
|
return {
|
|
47047
47962
|
port,
|
|
47048
|
-
run: (
|
|
47049
|
-
screenshot: (
|
|
47963
|
+
run: (fileKey3, call, timeoutMs) => request(fileKey3, { type: "run", ...call }, timeoutMs),
|
|
47964
|
+
screenshot: (fileKey3, call, timeoutMs) => request(fileKey3, { type: "screenshot", ...call }, timeoutMs),
|
|
47050
47965
|
close: () => new Promise((done) => {
|
|
47051
47966
|
if (!server || !bound)
|
|
47052
47967
|
return done();
|
|
@@ -47057,12 +47972,66 @@ async function startPluginBridge(options = {}) {
|
|
|
47057
47972
|
};
|
|
47058
47973
|
}
|
|
47059
47974
|
|
|
47975
|
+
// packages/zaku/dist/lib/domain/checks/libraries.js
|
|
47976
|
+
var comboKey2 = (combo) => JSON.stringify(Object.entries(combo).sort(([a], [b]) => a.localeCompare(b)));
|
|
47977
|
+
function joinLibraries(snapshots) {
|
|
47978
|
+
if (snapshots.length === 1 && snapshots[0])
|
|
47979
|
+
return snapshots[0];
|
|
47980
|
+
const tokens = /* @__PURE__ */ new Map();
|
|
47981
|
+
for (const snapshot of snapshots) {
|
|
47982
|
+
for (const token of snapshot.tokens) {
|
|
47983
|
+
const key = comboKey2(token.combo);
|
|
47984
|
+
tokens.set(key, { combo: token.combo, values: { ...tokens.get(key)?.values, ...token.values } });
|
|
47985
|
+
}
|
|
47986
|
+
}
|
|
47987
|
+
return {
|
|
47988
|
+
source: snapshots.map((snapshot) => snapshot.source).join(","),
|
|
47989
|
+
version: snapshots.map((snapshot) => snapshot.version).join(","),
|
|
47990
|
+
exportedAt: snapshots.map((snapshot) => snapshot.exportedAt).sort().at(-1) ?? "",
|
|
47991
|
+
components: snapshots.flatMap((snapshot) => snapshot.components),
|
|
47992
|
+
textStyles: snapshots.flatMap((snapshot) => snapshot.textStyles),
|
|
47993
|
+
tokens: [...tokens.values()]
|
|
47994
|
+
};
|
|
47995
|
+
}
|
|
47996
|
+
function missingSnapshots(graph, keys) {
|
|
47997
|
+
const paths = keys.map((key) => graph.legacy ? "library/index.json" : `library/${key}/index.json`);
|
|
47998
|
+
return `${paths.join(", ")} ${paths.length === 1 ? "is" : "are"} missing`;
|
|
47999
|
+
}
|
|
48000
|
+
function checkLibraries(input2) {
|
|
48001
|
+
const graph = designGraph(input2.config);
|
|
48002
|
+
const { libraries, missing } = snapshotsFor(input2);
|
|
48003
|
+
const kits = new Set(graph.kits.map((kit) => kit.key));
|
|
48004
|
+
const absent = missing.filter((key) => !kits.has(key));
|
|
48005
|
+
if (absent.length > 0)
|
|
48006
|
+
return { notRun: missingSnapshots(graph, absent) };
|
|
48007
|
+
if (libraries.length === 0)
|
|
48008
|
+
return { notRun: "library/index.json is missing" };
|
|
48009
|
+
const all = joinLibraries(libraries);
|
|
48010
|
+
const joined = /* @__PURE__ */ new Map();
|
|
48011
|
+
return {
|
|
48012
|
+
all,
|
|
48013
|
+
forTarget(targetId) {
|
|
48014
|
+
const target = input2.config.targets.find((candidate) => candidate.id === targetId);
|
|
48015
|
+
if (!target)
|
|
48016
|
+
return all;
|
|
48017
|
+
const cached2 = joined.get(targetId);
|
|
48018
|
+
if (cached2)
|
|
48019
|
+
return cached2;
|
|
48020
|
+
const own2 = joinLibraries(snapshotsFor(input2, target).libraries);
|
|
48021
|
+
joined.set(targetId, own2);
|
|
48022
|
+
return own2;
|
|
48023
|
+
}
|
|
48024
|
+
};
|
|
48025
|
+
}
|
|
48026
|
+
|
|
47060
48027
|
// packages/zaku/dist/lib/domain/checks/binding.js
|
|
47061
48028
|
var PAINTS = ["fill", "stroke", "textColor", "glyph"];
|
|
47062
48029
|
var SEMANTIC = /^(color|mode|radius)\//;
|
|
47063
|
-
var binding = (
|
|
47064
|
-
|
|
47065
|
-
|
|
48030
|
+
var binding = (input2) => {
|
|
48031
|
+
const libraries = checkLibraries(input2);
|
|
48032
|
+
if ("notRun" in libraries)
|
|
48033
|
+
return libraries;
|
|
48034
|
+
const library = libraries.all;
|
|
47066
48035
|
const findings = [];
|
|
47067
48036
|
for (const component2 of library.components) {
|
|
47068
48037
|
for (const variant of component2.variants) {
|
|
@@ -47428,8 +48397,9 @@ var frameCheck = ({ config: config2, outlines }) => {
|
|
|
47428
48397
|
}
|
|
47429
48398
|
return { findings };
|
|
47430
48399
|
};
|
|
47431
|
-
var systemBars = ({ config: config2, outlines }) => {
|
|
48400
|
+
var systemBars = ({ config: config2, outlines, kits }) => {
|
|
47432
48401
|
const families2 = new Map(config2.targets.map((target) => [target.id, target.family]));
|
|
48402
|
+
const graph = designGraph(config2);
|
|
47433
48403
|
const bars = { ...DEFAULT_SYSTEM_BARS, ...config2.systemBars };
|
|
47434
48404
|
const findings = [];
|
|
47435
48405
|
for (const outline of outlines) {
|
|
@@ -47437,7 +48407,10 @@ var systemBars = ({ config: config2, outlines }) => {
|
|
|
47437
48407
|
const family = families2.get(frame.target);
|
|
47438
48408
|
if (!family)
|
|
47439
48409
|
continue;
|
|
47440
|
-
const
|
|
48410
|
+
const own2 = graph.kits.filter((kit) => kit.family === family && kits[kit.key]);
|
|
48411
|
+
const kitKeys = new Set(own2.flatMap((kit) => kits[kit.key]?.components.map((component2) => component2.key) ?? []));
|
|
48412
|
+
const from = own2.length > 0 ? ` from ${own2.map((kit) => kit.key).join(" or ")}` : "";
|
|
48413
|
+
const held = new Set(frame.instances.filter((instance) => own2.length === 0 || kitKeys.has(instance.componentKey)).map((instance) => instance.component));
|
|
47441
48414
|
for (const names of bars[family]) {
|
|
47442
48415
|
if (!names.some((name) => held.has(name))) {
|
|
47443
48416
|
findings.push({
|
|
@@ -47446,7 +48419,7 @@ var systemBars = ({ config: config2, outlines }) => {
|
|
|
47446
48419
|
screen: outline.screen,
|
|
47447
48420
|
frame: frame.name,
|
|
47448
48421
|
nodeId: frame.nodeId,
|
|
47449
|
-
message: `no ${names.join(" or ")} instance on a ${family} frame`
|
|
48422
|
+
message: `no ${names.join(" or ")} instance${from} on a ${family} frame`
|
|
47450
48423
|
});
|
|
47451
48424
|
}
|
|
47452
48425
|
}
|
|
@@ -47460,6 +48433,18 @@ var placement = ({ maps, outlines }) => {
|
|
|
47460
48433
|
for (const outline of outlines) {
|
|
47461
48434
|
const title = titles.get(`${outline.feature}/${outline.screen}`);
|
|
47462
48435
|
for (const frame of outline.frames) {
|
|
48436
|
+
if (frame.page !== void 0) {
|
|
48437
|
+
if (title !== void 0 && frame.page !== title)
|
|
48438
|
+
findings.push({
|
|
48439
|
+
check: "placement",
|
|
48440
|
+
feature: outline.feature,
|
|
48441
|
+
screen: outline.screen,
|
|
48442
|
+
frame: frame.name,
|
|
48443
|
+
nodeId: frame.nodeId,
|
|
48444
|
+
message: `sits on the page ${frame.page}, and its screen is drawn on the page ${title}`
|
|
48445
|
+
});
|
|
48446
|
+
continue;
|
|
48447
|
+
}
|
|
47463
48448
|
const expected = [title, frame.state];
|
|
47464
48449
|
if (frame.containers.length !== 2 || frame.containers[0] !== expected[0] || frame.containers[1] !== expected[1]) {
|
|
47465
48450
|
findings.push({
|
|
@@ -47493,8 +48478,19 @@ var naming = ({ outlines }) => {
|
|
|
47493
48478
|
}
|
|
47494
48479
|
return { findings };
|
|
47495
48480
|
};
|
|
47496
|
-
var component = ({ outlines }) => {
|
|
48481
|
+
var component = ({ config: config2, outlines, productComponents }) => {
|
|
47497
48482
|
const findings = [];
|
|
48483
|
+
const graph = designGraph(config2);
|
|
48484
|
+
for (const drawn of productComponents) {
|
|
48485
|
+
const platform = graph.products.find((product) => product.key === drawn.source)?.platform;
|
|
48486
|
+
const branches = new Set(config2.targets.filter((target) => graph.platformOf(target) === platform).flatMap((target) => graph.branchOf(target) ?? []));
|
|
48487
|
+
const homes = graph.libraries.filter((library) => library.layer === "components" && library.branches.some((branch) => branches.has(branch))).map((library) => library.key);
|
|
48488
|
+
findings.push({
|
|
48489
|
+
check: "component",
|
|
48490
|
+
nodeId: drawn.nodeId,
|
|
48491
|
+
message: `${drawn.name} is a component on the product page ${drawn.page}; a product file draws screens only, so draw it in ${homes.length > 0 ? homes.join(" or ") : `a Components library of the ${[...branches].join(" or ")} branch`}`
|
|
48492
|
+
});
|
|
48493
|
+
}
|
|
47498
48494
|
for (const outline of outlines) {
|
|
47499
48495
|
const seen = /* @__PURE__ */ new Map();
|
|
47500
48496
|
for (const frame of outline.frames) {
|
|
@@ -47526,13 +48522,16 @@ var component = ({ outlines }) => {
|
|
|
47526
48522
|
};
|
|
47527
48523
|
|
|
47528
48524
|
// packages/zaku/dist/lib/domain/checks/font.js
|
|
47529
|
-
var font = (
|
|
47530
|
-
|
|
47531
|
-
|
|
47532
|
-
|
|
48525
|
+
var font = (input2) => {
|
|
48526
|
+
const libraries = checkLibraries(input2);
|
|
48527
|
+
if ("notRun" in libraries)
|
|
48528
|
+
return libraries;
|
|
48529
|
+
const keys = /* @__PURE__ */ new Map();
|
|
47533
48530
|
const findings = [];
|
|
47534
|
-
for (const outline of outlines) {
|
|
48531
|
+
for (const outline of input2.outlines) {
|
|
47535
48532
|
for (const frame of outline.frames) {
|
|
48533
|
+
const styles = keys.get(frame.target) ?? new Set(libraries.forTarget(frame.target).textStyles.map((style) => style.key));
|
|
48534
|
+
keys.set(frame.target, styles);
|
|
47536
48535
|
const where = { feature: outline.feature, screen: outline.screen, frame: frame.name };
|
|
47537
48536
|
for (const text of frame.texts) {
|
|
47538
48537
|
if (text.styleKey === null) {
|
|
@@ -47542,7 +48541,7 @@ var font = ({ outlines, library }) => {
|
|
|
47542
48541
|
nodeId: text.nodeId,
|
|
47543
48542
|
message: "text outside a component uses no library text style"
|
|
47544
48543
|
});
|
|
47545
|
-
} else if (!
|
|
48544
|
+
} else if (!styles.has(text.styleKey)) {
|
|
47546
48545
|
findings.push({
|
|
47547
48546
|
check: "font",
|
|
47548
48547
|
...where,
|
|
@@ -47557,8 +48556,9 @@ var font = ({ outlines, library }) => {
|
|
|
47557
48556
|
};
|
|
47558
48557
|
|
|
47559
48558
|
// packages/zaku/dist/lib/domain/checks/freshness.js
|
|
47560
|
-
var freshness = ({ maps, outlines,
|
|
48559
|
+
var freshness = ({ config: config2, maps, outlines, flows, libraries }) => {
|
|
47561
48560
|
const digests = new Map(maps.map((loaded) => [loaded.map.feature, loaded.digest]));
|
|
48561
|
+
const graph = designGraph(config2);
|
|
47562
48562
|
const findings = [];
|
|
47563
48563
|
for (const outline of outlines) {
|
|
47564
48564
|
const where = { feature: outline.feature, screen: outline.screen };
|
|
@@ -47570,11 +48570,35 @@ var freshness = ({ maps, outlines, library }) => {
|
|
|
47570
48570
|
message: "the map changed after this outline was read; run zaku outline"
|
|
47571
48571
|
});
|
|
47572
48572
|
}
|
|
47573
|
-
|
|
48573
|
+
for (const [key, library] of Object.entries(libraries)) {
|
|
48574
|
+
const read = outline.libraryVersions[key] ?? (graph.legacy ? outline.libraryVersions[LEGACY_LIBRARY_VERSION] : void 0);
|
|
48575
|
+
if (read === library.version)
|
|
48576
|
+
continue;
|
|
47574
48577
|
findings.push({
|
|
47575
48578
|
check: "freshness",
|
|
47576
48579
|
...where,
|
|
47577
|
-
message: "the library changed after this outline was read; run zaku outline"
|
|
48580
|
+
message: graph.legacy ? "the library changed after this outline was read; run zaku outline" : `library ${key} changed after this outline was read; run zaku outline`
|
|
48581
|
+
});
|
|
48582
|
+
}
|
|
48583
|
+
}
|
|
48584
|
+
const drawn = new Map(outlines.flatMap((outline) => outline.frames.map((frame) => [`${outline.feature}/${outline.screen}
|
|
48585
|
+
${frame.name}`, frame])));
|
|
48586
|
+
for (const page of flows) {
|
|
48587
|
+
for (const copy2 of page.frames) {
|
|
48588
|
+
if (copy2.screen === null)
|
|
48589
|
+
continue;
|
|
48590
|
+
const source = drawn.get(`${copy2.screen}
|
|
48591
|
+
${copy2.name}`);
|
|
48592
|
+
if (source?.digest === void 0 || source.digest === copy2.digest)
|
|
48593
|
+
continue;
|
|
48594
|
+
const [feature = "", screen = ""] = copy2.screen.split("/");
|
|
48595
|
+
findings.push({
|
|
48596
|
+
check: "freshness",
|
|
48597
|
+
feature,
|
|
48598
|
+
screen,
|
|
48599
|
+
frame: copy2.name,
|
|
48600
|
+
nodeId: copy2.nodeId,
|
|
48601
|
+
message: `the copy on the flow page ${page.page} differs from the frame it copies; copy it again`
|
|
47578
48602
|
});
|
|
47579
48603
|
}
|
|
47580
48604
|
}
|
|
@@ -47582,13 +48606,43 @@ var freshness = ({ maps, outlines, library }) => {
|
|
|
47582
48606
|
};
|
|
47583
48607
|
|
|
47584
48608
|
// packages/zaku/dist/lib/domain/checks/library.js
|
|
47585
|
-
|
|
47586
|
-
|
|
47587
|
-
|
|
48609
|
+
function frameFindings(input2) {
|
|
48610
|
+
const libraries = checkLibraries(input2);
|
|
48611
|
+
if ("notRun" in libraries)
|
|
48612
|
+
return libraries;
|
|
48613
|
+
const { config: config2, maps, outlines } = input2;
|
|
48614
|
+
const library = libraries.all;
|
|
47588
48615
|
const bars = systemBarNames(config2);
|
|
47589
48616
|
const owned = outlines.flatMap((outline) => outline.frames.flatMap((frame) => frame.instances.filter((instance) => instance.local).map((instance) => instance.component)));
|
|
47590
48617
|
const names = /* @__PURE__ */ new Set([...library.components.map((component2) => component2.name), ...owned]);
|
|
47591
48618
|
const keys = new Set(library.components.flatMap((component2) => component2.variants.map((variant) => variant.key)));
|
|
48619
|
+
const graph = designGraph(config2);
|
|
48620
|
+
const owners = /* @__PURE__ */ new Map();
|
|
48621
|
+
for (const [key, snapshot] of Object.entries(input2.libraries)) {
|
|
48622
|
+
const holds = graph.libraries.find((candidate) => candidate.key === key)?.branches ?? [];
|
|
48623
|
+
for (const component2 of snapshot.components) {
|
|
48624
|
+
const branches = component2.branch ? [component2.branch] : holds;
|
|
48625
|
+
for (const variant of component2.variants)
|
|
48626
|
+
owners.set(variant.key, `${key}, a ${branches.join(" and ")} library`);
|
|
48627
|
+
}
|
|
48628
|
+
}
|
|
48629
|
+
for (const [key, kit] of Object.entries(input2.kits)) {
|
|
48630
|
+
for (const component2 of kit.components)
|
|
48631
|
+
owners.set(component2.key, `${key}, an ${kit.family} kit`);
|
|
48632
|
+
}
|
|
48633
|
+
const allowed2 = /* @__PURE__ */ new Map();
|
|
48634
|
+
const allowedFor = (target) => {
|
|
48635
|
+
const cached2 = allowed2.get(target.id);
|
|
48636
|
+
if (cached2)
|
|
48637
|
+
return cached2;
|
|
48638
|
+
const { libraries: own2, kits } = snapshotsFor(input2, target);
|
|
48639
|
+
const set2 = /* @__PURE__ */ new Set([
|
|
48640
|
+
...own2.flatMap((snapshot) => snapshot.components.flatMap((component2) => component2.variants.map((v) => v.key))),
|
|
48641
|
+
...kits.flatMap((kit) => kit.components.map((component2) => component2.key))
|
|
48642
|
+
]);
|
|
48643
|
+
allowed2.set(target.id, set2);
|
|
48644
|
+
return set2;
|
|
48645
|
+
};
|
|
47592
48646
|
const findings = [];
|
|
47593
48647
|
for (const { map: map2 } of maps) {
|
|
47594
48648
|
for (const [id2, screen] of Object.entries(map2.screens)) {
|
|
@@ -47608,8 +48662,22 @@ var libraryCheck = ({ config: config2, maps, outlines, library }) => {
|
|
|
47608
48662
|
for (const outline of outlines) {
|
|
47609
48663
|
for (const frame of outline.frames) {
|
|
47610
48664
|
const where = { feature: outline.feature, screen: outline.screen, frame: frame.name };
|
|
48665
|
+
const target = config2.targets.find((candidate) => candidate.id === frame.target);
|
|
47611
48666
|
for (const instance of frame.instances) {
|
|
47612
|
-
if (
|
|
48667
|
+
if (instance.local)
|
|
48668
|
+
continue;
|
|
48669
|
+
const owner = owners.get(instance.componentKey);
|
|
48670
|
+
if (target && owner && !allowedFor(target).has(instance.componentKey)) {
|
|
48671
|
+
const draws = owner.endsWith(" kit") ? `${target.family} kits` : graph.branchOf(target) ?? "no branch";
|
|
48672
|
+
findings.push({
|
|
48673
|
+
check: "library",
|
|
48674
|
+
...where,
|
|
48675
|
+
nodeId: instance.nodeId,
|
|
48676
|
+
message: `an instance of ${instance.component} comes from ${owner}; a ${target.name} frame draws from ${draws}`
|
|
48677
|
+
});
|
|
48678
|
+
continue;
|
|
48679
|
+
}
|
|
48680
|
+
if (!bars.has(instance.component) && !keys.has(instance.componentKey) && !owner) {
|
|
47613
48681
|
findings.push({
|
|
47614
48682
|
check: "library",
|
|
47615
48683
|
...where,
|
|
@@ -47629,6 +48697,82 @@ var libraryCheck = ({ config: config2, maps, outlines, library }) => {
|
|
|
47629
48697
|
}
|
|
47630
48698
|
}
|
|
47631
48699
|
return { findings };
|
|
48700
|
+
}
|
|
48701
|
+
function referable(snapshot) {
|
|
48702
|
+
return {
|
|
48703
|
+
variable: Object.values(snapshot.variableKeys ?? {}).flatMap((variable) => variable.local ? [variable.key] : []),
|
|
48704
|
+
"text style": snapshot.textStyles.map((style) => style.key),
|
|
48705
|
+
"effect style": (snapshot.effectStyles ?? []).map((style) => style.key),
|
|
48706
|
+
instance: snapshot.components.flatMap((component2) => [
|
|
48707
|
+
component2.key,
|
|
48708
|
+
...component2.variants.map((variant) => variant.key)
|
|
48709
|
+
])
|
|
48710
|
+
};
|
|
48711
|
+
}
|
|
48712
|
+
function referenceFindings(input2) {
|
|
48713
|
+
const graph = designGraph(input2.config);
|
|
48714
|
+
const findings = [];
|
|
48715
|
+
for (const [key, snapshot] of Object.entries(input2.libraries)) {
|
|
48716
|
+
if (!snapshot.variableKeys)
|
|
48717
|
+
continue;
|
|
48718
|
+
const bases = graph.closure(key).slice(1);
|
|
48719
|
+
const missing = bases.filter((base) => !input2.libraries[base] && !input2.kits[base]);
|
|
48720
|
+
if (missing.length > 0) {
|
|
48721
|
+
const paths = missing.map((base) => graph.kits.some((kit) => kit.key === base) ? `library/${base}/kit.json` : `library/${base}/index.json`);
|
|
48722
|
+
return { notRun: `${paths.join(", ")} ${paths.length === 1 ? "is" : "are"} missing` };
|
|
48723
|
+
}
|
|
48724
|
+
const allowed2 = {
|
|
48725
|
+
variable: /* @__PURE__ */ new Set(),
|
|
48726
|
+
"text style": /* @__PURE__ */ new Set(),
|
|
48727
|
+
"effect style": /* @__PURE__ */ new Set(),
|
|
48728
|
+
instance: new Set(snapshot.localComponents ?? [])
|
|
48729
|
+
};
|
|
48730
|
+
for (const from of [key, ...bases]) {
|
|
48731
|
+
const library = input2.libraries[from];
|
|
48732
|
+
if (library)
|
|
48733
|
+
for (const [kind, keys] of Object.entries(referable(library)))
|
|
48734
|
+
for (const ref of keys)
|
|
48735
|
+
allowed2[kind].add(ref);
|
|
48736
|
+
for (const component2 of input2.kits[from]?.components ?? [])
|
|
48737
|
+
allowed2.instance.add(component2.key);
|
|
48738
|
+
}
|
|
48739
|
+
const extended2 = bases.length > 0 ? `from ${bases.join(", ")}` : "from a library it extends, and it extends none";
|
|
48740
|
+
for (const component2 of snapshot.components) {
|
|
48741
|
+
for (const variant of component2.variants) {
|
|
48742
|
+
for (const item of variant.modes[0]?.items ?? []) {
|
|
48743
|
+
const refs = [
|
|
48744
|
+
...(item.variableIds ?? []).map((id2) => [
|
|
48745
|
+
"variable",
|
|
48746
|
+
snapshot.variableKeys?.[id2]?.key ?? id2
|
|
48747
|
+
]),
|
|
48748
|
+
...item.textStyleKey ? [["text style", item.textStyleKey]] : [],
|
|
48749
|
+
...item.effectStyleKey ? [["effect style", item.effectStyleKey]] : [],
|
|
48750
|
+
...item.componentKey ? [["instance", item.componentKey]] : []
|
|
48751
|
+
];
|
|
48752
|
+
for (const [kind, ref] of refs) {
|
|
48753
|
+
if (allowed2[kind].has(ref))
|
|
48754
|
+
continue;
|
|
48755
|
+
findings.push({
|
|
48756
|
+
check: "library",
|
|
48757
|
+
nodeId: item.nodeId,
|
|
48758
|
+
field: "references",
|
|
48759
|
+
message: `${key}: ${component2.name} ${variant.name} ${item.path || "(root)"}: ${kind} ${ref} is neither the library's own nor ${extended2}`
|
|
48760
|
+
});
|
|
48761
|
+
}
|
|
48762
|
+
}
|
|
48763
|
+
}
|
|
48764
|
+
}
|
|
48765
|
+
}
|
|
48766
|
+
return { findings };
|
|
48767
|
+
}
|
|
48768
|
+
var libraryCheck = (input2) => {
|
|
48769
|
+
const frames = frameFindings(input2);
|
|
48770
|
+
if ("notRun" in frames)
|
|
48771
|
+
return frames;
|
|
48772
|
+
const references = referenceFindings(input2);
|
|
48773
|
+
if ("notRun" in references)
|
|
48774
|
+
return references;
|
|
48775
|
+
return { findings: [...frames.findings, ...references.findings] };
|
|
47632
48776
|
};
|
|
47633
48777
|
|
|
47634
48778
|
// packages/zaku/dist/lib/domain/checks/navigation.js
|
|
@@ -47699,7 +48843,11 @@ var ALLOWED_OVERRIDES = /* @__PURE__ */ new Set([
|
|
|
47699
48843
|
"name",
|
|
47700
48844
|
"componentProperties",
|
|
47701
48845
|
"componentPropertyReferences",
|
|
47702
|
-
"exposedInstances"
|
|
48846
|
+
"exposedInstances",
|
|
48847
|
+
"reactions",
|
|
48848
|
+
"transitionNodeID",
|
|
48849
|
+
"transitionDuration",
|
|
48850
|
+
"transitionEasing"
|
|
47703
48851
|
]);
|
|
47704
48852
|
var SIZING_MODES = /* @__PURE__ */ new Set(["primaryAxisSizingMode", "counterAxisSizingMode"]);
|
|
47705
48853
|
function componentSized(field, size2, main2) {
|
|
@@ -47713,9 +48861,12 @@ function stretches(sizing) {
|
|
|
47713
48861
|
function insideSwap(instance, nodeId) {
|
|
47714
48862
|
return instance.nested.some((nested) => nodeId.startsWith(`${nested.nodeId};`) && instance.swaps.includes(nested.componentKey));
|
|
47715
48863
|
}
|
|
47716
|
-
var overrides = (
|
|
47717
|
-
|
|
47718
|
-
|
|
48864
|
+
var overrides = (input2) => {
|
|
48865
|
+
const libraries = checkLibraries(input2);
|
|
48866
|
+
if ("notRun" in libraries)
|
|
48867
|
+
return libraries;
|
|
48868
|
+
const { outlines } = input2;
|
|
48869
|
+
const library = libraries.all;
|
|
47719
48870
|
const nestedOf = /* @__PURE__ */ new Map();
|
|
47720
48871
|
const componentOf = /* @__PURE__ */ new Map();
|
|
47721
48872
|
for (const component2 of library.components) {
|
|
@@ -47776,18 +48927,58 @@ var overrides = ({ outlines, library }) => {
|
|
|
47776
48927
|
return { findings };
|
|
47777
48928
|
};
|
|
47778
48929
|
|
|
48930
|
+
// packages/zaku/dist/lib/domain/flows.js
|
|
48931
|
+
function flowsOf(maps) {
|
|
48932
|
+
const index = indexScreens(maps);
|
|
48933
|
+
const flows = [];
|
|
48934
|
+
for (const root of index.values()) {
|
|
48935
|
+
if (!root.screen.root)
|
|
48936
|
+
continue;
|
|
48937
|
+
const screens = [root];
|
|
48938
|
+
for (let at = 0; at < screens.length; at += 1) {
|
|
48939
|
+
const from = screens[at];
|
|
48940
|
+
if (!from)
|
|
48941
|
+
continue;
|
|
48942
|
+
for (const exit of from.screen.exits) {
|
|
48943
|
+
const next = index.get(qualify(exit.to, from.feature));
|
|
48944
|
+
if (next && !screens.includes(next))
|
|
48945
|
+
screens.push(next);
|
|
48946
|
+
}
|
|
48947
|
+
}
|
|
48948
|
+
flows.push({ root, screens });
|
|
48949
|
+
}
|
|
48950
|
+
return flows;
|
|
48951
|
+
}
|
|
48952
|
+
|
|
47779
48953
|
// packages/zaku/dist/lib/domain/checks/prototype.js
|
|
47780
|
-
|
|
47781
|
-
if (
|
|
47782
|
-
return
|
|
48954
|
+
function legacyScreens(input2) {
|
|
48955
|
+
if (input2.flows.length === 0)
|
|
48956
|
+
return input2.outlines;
|
|
48957
|
+
const byScreen = /* @__PURE__ */ new Map();
|
|
48958
|
+
for (const page of input2.flows) {
|
|
48959
|
+
for (const frame of page.frames) {
|
|
48960
|
+
if (frame.screen === null)
|
|
48961
|
+
continue;
|
|
48962
|
+
const [feature = "", screen = ""] = frame.screen.split("/");
|
|
48963
|
+
const entry = byScreen.get(frame.screen) ?? { feature, screen, frames: [] };
|
|
48964
|
+
entry.frames.push(frame);
|
|
48965
|
+
byScreen.set(frame.screen, entry);
|
|
48966
|
+
}
|
|
48967
|
+
}
|
|
48968
|
+
return [...byScreen.values()];
|
|
48969
|
+
}
|
|
48970
|
+
function legacyFindings(input2) {
|
|
48971
|
+
const screens = legacyScreens(input2);
|
|
48972
|
+
if (screens.length === 0)
|
|
48973
|
+
return [];
|
|
47783
48974
|
const screenOfFrame = /* @__PURE__ */ new Map();
|
|
47784
|
-
const outlineOf = new Map(
|
|
47785
|
-
for (const outline of
|
|
48975
|
+
const outlineOf = new Map(screens.map((outline) => [`${outline.feature}/${outline.screen}`, outline]));
|
|
48976
|
+
for (const outline of screens) {
|
|
47786
48977
|
for (const frame of outline.frames)
|
|
47787
48978
|
screenOfFrame.set(frame.nodeId, `${outline.feature}/${outline.screen}`);
|
|
47788
48979
|
}
|
|
47789
48980
|
const findings = [];
|
|
47790
|
-
for (const { map: map2 } of maps) {
|
|
48981
|
+
for (const { map: map2 } of input2.maps) {
|
|
47791
48982
|
for (const [id2, screen] of Object.entries(map2.screens)) {
|
|
47792
48983
|
const outline = outlineOf.get(`${map2.feature}/${id2}`);
|
|
47793
48984
|
if (!outline)
|
|
@@ -47824,8 +49015,64 @@ var prototype = ({ maps, outlines }) => {
|
|
|
47824
49015
|
}
|
|
47825
49016
|
}
|
|
47826
49017
|
}
|
|
47827
|
-
return
|
|
47828
|
-
}
|
|
49018
|
+
return findings;
|
|
49019
|
+
}
|
|
49020
|
+
function flowFindings(input2) {
|
|
49021
|
+
const prototypes = new Set(designGraph(input2.config).prototypes.map((file2) => file2.key));
|
|
49022
|
+
const findings = [];
|
|
49023
|
+
for (const flow of flowsOf(input2.maps)) {
|
|
49024
|
+
const { root } = flow;
|
|
49025
|
+
const title = root.screen.title;
|
|
49026
|
+
const keyOf = (ref) => `${ref.feature}/${ref.id}`;
|
|
49027
|
+
const pages = input2.flows.filter((page) => page.page === title && prototypes.has(page.source));
|
|
49028
|
+
if (pages.length === 0) {
|
|
49029
|
+
findings.push({
|
|
49030
|
+
check: "prototype",
|
|
49031
|
+
feature: root.feature,
|
|
49032
|
+
screen: root.id,
|
|
49033
|
+
message: `no flow page is named ${title}`
|
|
49034
|
+
});
|
|
49035
|
+
continue;
|
|
49036
|
+
}
|
|
49037
|
+
const inFlow = new Set(flow.screens.map(keyOf));
|
|
49038
|
+
for (const page of pages) {
|
|
49039
|
+
const screenOf = new Map(page.frames.map((frame) => [frame.nodeId, frame.screen]));
|
|
49040
|
+
const first = root.screen.states[0];
|
|
49041
|
+
if (!page.frames.some((frame) => frame.screen === keyOf(root) && frame.state === first && frame.start))
|
|
49042
|
+
findings.push({
|
|
49043
|
+
check: "prototype",
|
|
49044
|
+
feature: root.feature,
|
|
49045
|
+
screen: root.id,
|
|
49046
|
+
message: `the flow page ${title} does not start on ${title}'s first state`
|
|
49047
|
+
});
|
|
49048
|
+
for (const ref of flow.screens) {
|
|
49049
|
+
const where = { check: "prototype", feature: ref.feature, screen: ref.id };
|
|
49050
|
+
const copies = page.frames.filter((frame) => frame.screen === keyOf(ref));
|
|
49051
|
+
for (const exit of ref.screen.exits) {
|
|
49052
|
+
const target = qualify(exit.to, ref.feature);
|
|
49053
|
+
if (!inFlow.has(target))
|
|
49054
|
+
continue;
|
|
49055
|
+
const connected = copies.some((frame) => frame.links.some((link) => link.to !== "back" && screenOf.get(link.to.nodeId) === target));
|
|
49056
|
+
if (!connected)
|
|
49057
|
+
findings.push({
|
|
49058
|
+
...where,
|
|
49059
|
+
field: "exits",
|
|
49060
|
+
message: `on the flow page ${title}, the exit to ${exit.to} (${exit.via}) has no connection`
|
|
49061
|
+
});
|
|
49062
|
+
}
|
|
49063
|
+
if (ref !== root && copies.length > 0 && !copies.some((frame) => frame.links.some((link) => link.to === "back")))
|
|
49064
|
+
findings.push({
|
|
49065
|
+
...where,
|
|
49066
|
+
message: `on the flow page ${title}, a screen that is not the root has no Back action`
|
|
49067
|
+
});
|
|
49068
|
+
}
|
|
49069
|
+
}
|
|
49070
|
+
}
|
|
49071
|
+
return findings;
|
|
49072
|
+
}
|
|
49073
|
+
var prototype = (input2) => ({
|
|
49074
|
+
findings: designGraph(input2.config).prototypes.length > 0 ? flowFindings(input2) : legacyFindings(input2)
|
|
49075
|
+
});
|
|
47829
49076
|
|
|
47830
49077
|
// packages/zaku/dist/lib/domain/checks/recipe.js
|
|
47831
49078
|
function propsLabel(props) {
|
|
@@ -47845,7 +49092,7 @@ var GENERIC = /* @__PURE__ */ new Set(["serif", "sans-serif", "monospace", "curs
|
|
|
47845
49092
|
function families(stack) {
|
|
47846
49093
|
return stack.split(",").map((family) => family.trim().replace(/^["']|["']$/g, "")).filter((family) => family !== "" && !GENERIC.has(family.toLowerCase()));
|
|
47847
49094
|
}
|
|
47848
|
-
function
|
|
49095
|
+
function colour2(at, field, library, code) {
|
|
47849
49096
|
const transparent = { r: 0, g: 0, b: 0, a: 0 };
|
|
47850
49097
|
const drawn = library ?? transparent;
|
|
47851
49098
|
const coded = code ?? transparent;
|
|
@@ -47874,12 +49121,12 @@ function size(at, field, library, code) {
|
|
|
47874
49121
|
}
|
|
47875
49122
|
function comparePart(at, part) {
|
|
47876
49123
|
const { item } = at;
|
|
47877
|
-
|
|
49124
|
+
colour2(at, "background", item.fill, part.background);
|
|
47878
49125
|
if (item.type.toUpperCase() === "TEXT")
|
|
47879
|
-
|
|
47880
|
-
|
|
49126
|
+
colour2(at, "color", item.textColor, part.color);
|
|
49127
|
+
colour2(at, "borderColor", item.stroke, part.borderColor);
|
|
47881
49128
|
if (item.glyph)
|
|
47882
|
-
|
|
49129
|
+
colour2(at, "glyph", item.glyph, part.color);
|
|
47883
49130
|
if (item.path === "") {
|
|
47884
49131
|
if (!at.fallback)
|
|
47885
49132
|
size(at, "width", item.width, part.width);
|
|
@@ -47905,9 +49152,14 @@ function comparePart(at, part) {
|
|
|
47905
49152
|
});
|
|
47906
49153
|
}
|
|
47907
49154
|
}
|
|
47908
|
-
var recipe = (
|
|
47909
|
-
|
|
47910
|
-
|
|
49155
|
+
var recipe = (input2) => {
|
|
49156
|
+
const { config: config2, recipe: doc } = input2;
|
|
49157
|
+
const libraries = checkLibraries(input2);
|
|
49158
|
+
if ("notRun" in libraries)
|
|
49159
|
+
return doc ? libraries : { notRun: `recipe.json or ${libraries.notRun}` };
|
|
49160
|
+
if (!doc)
|
|
49161
|
+
return { notRun: "recipe.json is missing" };
|
|
49162
|
+
const library = libraries.all;
|
|
47911
49163
|
const findings = [];
|
|
47912
49164
|
for (const code of doc.components) {
|
|
47913
49165
|
const component2 = library.components.find((candidate) => candidate.name === code.name);
|
|
@@ -47998,9 +49250,12 @@ var MIN_TARGET = {
|
|
|
47998
49250
|
function controlsOf(frame) {
|
|
47999
49251
|
return frame.instances.flatMap((instance) => [instance, ...instance.nested].flatMap((control) => control.interactive && control.bounds ? [{ nodeId: control.nodeId, componentKey: control.componentKey, bounds: control.bounds }] : []));
|
|
48000
49252
|
}
|
|
48001
|
-
var targetSize = (
|
|
48002
|
-
|
|
48003
|
-
|
|
49253
|
+
var targetSize = (input2) => {
|
|
49254
|
+
const libraries = checkLibraries(input2);
|
|
49255
|
+
if ("notRun" in libraries)
|
|
49256
|
+
return libraries;
|
|
49257
|
+
const { config: config2, outlines } = input2;
|
|
49258
|
+
const library = libraries.all;
|
|
48004
49259
|
const presetHeight = /* @__PURE__ */ new Map();
|
|
48005
49260
|
for (const component2 of library.components) {
|
|
48006
49261
|
for (const variant of component2.variants) {
|
|
@@ -48082,9 +49337,14 @@ function rgbaOf(token) {
|
|
|
48082
49337
|
const [r, g, b] = token.$value.components;
|
|
48083
49338
|
return { r, g, b, a: token.$value.alpha };
|
|
48084
49339
|
}
|
|
48085
|
-
var tokensCheck = (
|
|
48086
|
-
|
|
48087
|
-
|
|
49340
|
+
var tokensCheck = (input2) => {
|
|
49341
|
+
const { config: config2, tokens } = input2;
|
|
49342
|
+
const libraries = checkLibraries(input2);
|
|
49343
|
+
if ("notRun" in libraries)
|
|
49344
|
+
return libraries;
|
|
49345
|
+
if (!tokens)
|
|
49346
|
+
return { notRun: "tokens.json is missing" };
|
|
49347
|
+
const library = libraries.all;
|
|
48088
49348
|
const sets = tokenSets(tokens);
|
|
48089
49349
|
const findings = [];
|
|
48090
49350
|
for (const [scheme, set2] of [
|
|
@@ -48388,13 +49648,25 @@ async function loadDesign(root) {
|
|
|
48388
49648
|
message: `two screens share the title ${title}; a frame name could not tell them apart`
|
|
48389
49649
|
});
|
|
48390
49650
|
}
|
|
48391
|
-
const { outlines, unmapped, errors: outlineErrors } = await loadOutlines(paths.outline);
|
|
49651
|
+
const { outlines, flows, unmapped, errors: outlineErrors } = await loadOutlines(paths.outline);
|
|
48392
49652
|
findings.push(...outlineErrors.map(schemaFinding));
|
|
48393
|
-
const
|
|
49653
|
+
const { libraries, kits, errors: snapshotErrors } = await readDesignSnapshots(paths, config2);
|
|
49654
|
+
findings.push(...snapshotErrors.map(schemaFinding));
|
|
48394
49655
|
const tokens = await optional3(() => readOptionalDesignFile(paths.tokens, tokenDocumentSchema), findings);
|
|
48395
49656
|
const recipe2 = await optional3(() => readOptionalDesignFile(paths.recipe, recipeDocumentSchema), findings);
|
|
48396
49657
|
return {
|
|
48397
|
-
input: {
|
|
49658
|
+
input: {
|
|
49659
|
+
config: config2,
|
|
49660
|
+
maps,
|
|
49661
|
+
outlines,
|
|
49662
|
+
flows,
|
|
49663
|
+
unmapped: unmapped?.frames ?? [],
|
|
49664
|
+
productComponents: unmapped?.components ?? [],
|
|
49665
|
+
libraries,
|
|
49666
|
+
kits,
|
|
49667
|
+
tokens,
|
|
49668
|
+
recipe: recipe2
|
|
49669
|
+
},
|
|
48398
49670
|
findings
|
|
48399
49671
|
};
|
|
48400
49672
|
}
|
|
@@ -48429,6 +49701,7 @@ function refusalOf(error62) {
|
|
|
48429
49701
|
}
|
|
48430
49702
|
if (error62 instanceof FigmaFileKeyMissing) return { code: 3, line: error62.message };
|
|
48431
49703
|
if (error62 instanceof FigmaTokenMissing) return { code: 3, line: error62.message };
|
|
49704
|
+
if (error62 instanceof LibraryKeyMissing) return { code: 3, line: error62.message };
|
|
48432
49705
|
if (error62 instanceof RecipePageFailed) return { code: 2, line: `zaku recipe: ${error62.message}` };
|
|
48433
49706
|
return null;
|
|
48434
49707
|
}
|
|
@@ -58116,35 +59389,35 @@ var StdioServerTransport = class {
|
|
|
58116
59389
|
};
|
|
58117
59390
|
|
|
58118
59391
|
// apps/zaku-cli/src/mcp/server.ts
|
|
58119
|
-
import { mkdir as
|
|
59392
|
+
import { mkdir as mkdir5 } from "node:fs/promises";
|
|
58120
59393
|
import { tmpdir } from "node:os";
|
|
58121
|
-
import { join as
|
|
59394
|
+
import { join as join11 } from "node:path";
|
|
58122
59395
|
|
|
58123
59396
|
// apps/zaku-cli/src/mcp/screenshots.ts
|
|
58124
|
-
import { readdir as
|
|
58125
|
-
import { join as
|
|
59397
|
+
import { readdir as readdir4, rm as rm3, stat } from "node:fs/promises";
|
|
59398
|
+
import { join as join9 } from "node:path";
|
|
58126
59399
|
var KEPT_MS = 24 * 60 * 60 * 1e3;
|
|
58127
59400
|
async function pruneScreenshots(dir, now) {
|
|
58128
59401
|
let names;
|
|
58129
59402
|
try {
|
|
58130
|
-
names = await
|
|
59403
|
+
names = await readdir4(dir);
|
|
58131
59404
|
} catch {
|
|
58132
59405
|
return;
|
|
58133
59406
|
}
|
|
58134
59407
|
for (const name of names.filter((entry) => entry.endsWith(".png"))) {
|
|
58135
|
-
const path2 =
|
|
59408
|
+
const path2 = join9(dir, name);
|
|
58136
59409
|
const written = await stat(path2).then(
|
|
58137
59410
|
(stats) => stats.mtimeMs,
|
|
58138
59411
|
() => now
|
|
58139
59412
|
);
|
|
58140
|
-
if (now - written > KEPT_MS) await
|
|
59413
|
+
if (now - written > KEPT_MS) await rm3(path2, { force: true });
|
|
58141
59414
|
}
|
|
58142
59415
|
}
|
|
58143
59416
|
|
|
58144
59417
|
// apps/zaku-cli/src/mcp/tools.ts
|
|
58145
59418
|
import { writeFile as writeFile5 } from "node:fs/promises";
|
|
58146
|
-
import { join as
|
|
58147
|
-
var
|
|
59419
|
+
import { join as join10 } from "node:path";
|
|
59420
|
+
var fileKey2 = external_exports.string().min(1).regex(/^[0-9a-zA-Z]{22,128}$/).describe(
|
|
58148
59421
|
"The key of the Figma file to use. If the URL is provided, extract the file key from the URL: https://figma.com/design/:fileKey/:fileName."
|
|
58149
59422
|
);
|
|
58150
59423
|
var FALLBACK = "zaku's fallback for Figma's MCP server: the same tool and input, run in the file through the zaku plugin, which the person has open in that file with its key given.";
|
|
@@ -58156,7 +59429,7 @@ function registerFigmaTools(server, bridge, options) {
|
|
|
58156
59429
|
inputSchema: external_exports.object({
|
|
58157
59430
|
code: external_exports.string().max(5e4).describe("JavaScript code to execute. Has access to the `figma` global (Figma Plugin API)"),
|
|
58158
59431
|
description: external_exports.string().max(2e3).describe("A concise description of what the code aims to do"),
|
|
58159
|
-
fileKey,
|
|
59432
|
+
fileKey: fileKey2,
|
|
58160
59433
|
skillNames: external_exports.string().optional().describe("A comma-separated list of Figma skill names being followed, if any.")
|
|
58161
59434
|
}).strict()
|
|
58162
59435
|
},
|
|
@@ -58174,7 +59447,7 @@ function registerFigmaTools(server, bridge, options) {
|
|
|
58174
59447
|
inputSchema: external_exports.object({
|
|
58175
59448
|
contentsOnly: external_exports.boolean().optional().describe("When true, renders the node in isolation. Defaults to false."),
|
|
58176
59449
|
enableBase64Response: external_exports.boolean().default(false).describe("When true, the response also includes the screenshot inline as a base64-encoded image entry."),
|
|
58177
|
-
fileKey,
|
|
59450
|
+
fileKey: fileKey2,
|
|
58178
59451
|
maxDimension: external_exports.number().int().max(65536).default(1024).describe("Maximum pixel size of the longer edge of the rendered screenshot. Defaults to 1024."),
|
|
58179
59452
|
nodeId: external_exports.string().min(1).regex(/^\d+[:-]\d+$/).describe('The ID of the node in the Figma document, eg. "123:456" or "123-456".')
|
|
58180
59453
|
}).strict()
|
|
@@ -58187,7 +59460,7 @@ function registerFigmaTools(server, bridge, options) {
|
|
|
58187
59460
|
options.timeoutMs
|
|
58188
59461
|
);
|
|
58189
59462
|
if (!answer.ok) return { isError: true, content: [{ type: "text", text: answer.error }] };
|
|
58190
|
-
const path2 =
|
|
59463
|
+
const path2 = join10(options.imageDir, `${id2.replace(":", "-")}-${Date.now()}.png`);
|
|
58191
59464
|
await writeFile5(path2, Buffer.from(answer.png, "base64"));
|
|
58192
59465
|
const text = JSON.stringify({
|
|
58193
59466
|
path: path2,
|
|
@@ -58213,8 +59486,8 @@ async function serveMcp(log) {
|
|
|
58213
59486
|
log(
|
|
58214
59487
|
bridge.port === null ? "zaku mcp: no port from 7337 to 7346 was free; every call will say so" : `zaku mcp: listening for the zaku plugin on localhost:${bridge.port}`
|
|
58215
59488
|
);
|
|
58216
|
-
const imageDir =
|
|
58217
|
-
await
|
|
59489
|
+
const imageDir = join11(tmpdir(), "zaku-screenshots");
|
|
59490
|
+
await mkdir5(imageDir, { recursive: true });
|
|
58218
59491
|
await pruneScreenshots(imageDir, Date.now());
|
|
58219
59492
|
const server = new McpServer({ name: "zaku", version: "1" });
|
|
58220
59493
|
registerFigmaTools(server, bridge, { timeoutMs: CALL_TIMEOUT_MS, imageDir, log });
|
|
@@ -58230,7 +59503,7 @@ async function serveMcp(log) {
|
|
|
58230
59503
|
|
|
58231
59504
|
// apps/zaku-cli/src/cli.ts
|
|
58232
59505
|
var USE_FIGMA_CODE_LIMIT = 5e4;
|
|
58233
|
-
var USAGE = "usage: zaku <check|outline|tokens|recipe|library|rules|budget|schema|mcp> [--root docs/design]";
|
|
59506
|
+
var USAGE = "usage: zaku <check|outline|tokens|recipe|library|libraries|rules|budget|schema|mcp> [--root docs/design]";
|
|
58234
59507
|
async function sendOrRefuse(cli, io, finish, command) {
|
|
58235
59508
|
try {
|
|
58236
59509
|
return await cli.bus.send(command);
|
|
@@ -58248,6 +59521,14 @@ async function recordRestCalls(cli, io) {
|
|
|
58248
59521
|
const { seat, run } = seatAndRun(io.env);
|
|
58249
59522
|
await cli.bus.send(new RecordBudgetCalls({ day: today(clock.now()), seat, run, kind: "rest", count }));
|
|
58250
59523
|
}
|
|
59524
|
+
var librariesCommand = (program2, io, finish) => {
|
|
59525
|
+
program2.command("libraries").description("print the design graph: what each target draws from, and what each file extends and is extended by").option("--root <dir>", "the design directory", "docs/design").action(async (options) => {
|
|
59526
|
+
const paths = designPaths(resolve2(io.cwd, options.root));
|
|
59527
|
+
const config2 = await readDesignFile(paths.config, zakuConfigSchema);
|
|
59528
|
+
for (const line of printGraph(config2, await readDesignSnapshots(paths, config2))) io.out(line);
|
|
59529
|
+
finish(0);
|
|
59530
|
+
});
|
|
59531
|
+
};
|
|
58251
59532
|
var schemaCommand = (program2, io, finish, cli) => {
|
|
58252
59533
|
program2.command("schema").description("write the JSON Schemas an editor reads for the design files").option("--out <dir>", "where to write them", "docs/design").action(async (options) => {
|
|
58253
59534
|
const written = await cli.bus.send(new WriteSchemas({ out: resolve2(io.cwd, options.out) }));
|
|
@@ -58260,7 +59541,7 @@ var checkCommand = (program2, io, finish) => {
|
|
|
58260
59541
|
const loaded = await loadDesign(resolve2(io.cwd, options.root));
|
|
58261
59542
|
const report = loaded.input ? runChecks(loaded.input, ALL_CHECKS) : { findings: [], notRun: [], passed: [] };
|
|
58262
59543
|
report.findings.unshift(...loaded.findings);
|
|
58263
|
-
const ran = options.input ? parseDesignFile(options.input, await
|
|
59544
|
+
const ran = options.input ? parseDesignFile(options.input, await readFile6(resolve2(io.cwd, options.input), "utf8"), rulesAnswerSchema) : null;
|
|
58264
59545
|
if (ran && "rulesError" in ran) {
|
|
58265
59546
|
io.err(`zaku check: the rules did not run after the write: ${ran.rulesError}`);
|
|
58266
59547
|
finish(1);
|
|
@@ -58274,7 +59555,7 @@ var checkCommand = (program2, io, finish) => {
|
|
|
58274
59555
|
});
|
|
58275
59556
|
};
|
|
58276
59557
|
async function productPlaywright(cwd) {
|
|
58277
|
-
const require2 = createRequire(
|
|
59558
|
+
const require2 = createRequire(join12(cwd, "package.json"));
|
|
58278
59559
|
let resolved;
|
|
58279
59560
|
try {
|
|
58280
59561
|
resolved = require2.resolve("playwright");
|
|
@@ -58286,14 +59567,14 @@ async function productPlaywright(cwd) {
|
|
|
58286
59567
|
}
|
|
58287
59568
|
function fromProductTree(cwd, resolved) {
|
|
58288
59569
|
for (let dir = resolve2(cwd); ; dir = dirname4(dir)) {
|
|
58289
|
-
if (resolved.startsWith(
|
|
59570
|
+
if (resolved.startsWith(join12(dir, "node_modules") + sep)) return true;
|
|
58290
59571
|
if (dirname4(dir) === dir) return false;
|
|
58291
59572
|
}
|
|
58292
59573
|
}
|
|
58293
59574
|
var runners = {
|
|
58294
59575
|
run: execRun,
|
|
58295
59576
|
loadPlaywright: productPlaywright,
|
|
58296
|
-
rulesLibrary: () =>
|
|
59577
|
+
rulesLibrary: () => readFile6(fileURLToPath(new URL("./rules.js", import.meta.url)), "utf8")
|
|
58297
59578
|
};
|
|
58298
59579
|
var mcpCommand = (program2, io, finish) => {
|
|
58299
59580
|
program2.command("mcp").description(
|
|
@@ -58411,13 +59692,26 @@ var libraryCommand = (program2, io, finish, cli) => {
|
|
|
58411
59692
|
finish(0);
|
|
58412
59693
|
}
|
|
58413
59694
|
);
|
|
58414
|
-
library.command("save").description(
|
|
59695
|
+
library.command("save").description(
|
|
59696
|
+
"write a library's snapshot from its components over Figma REST, joined to the variables export, or a kit's published components"
|
|
59697
|
+
).option("--root <dir>", "the design directory", "docs/design").option("--key <key>", "the library or kit to save, as zaku.yaml lists it; needed when it lists several").option(
|
|
58415
59698
|
"--input <variables.json>",
|
|
58416
59699
|
"what use_figma returned for zaku library script; once per page export for a library in the product file",
|
|
58417
59700
|
(value, previous = []) => [...previous, value]
|
|
58418
59701
|
).action(async (options) => {
|
|
58419
59702
|
const root = resolve2(io.cwd, options.root);
|
|
58420
|
-
|
|
59703
|
+
const config2 = await readDesignFile(designPaths(root).config, zakuConfigSchema);
|
|
59704
|
+
let target;
|
|
59705
|
+
try {
|
|
59706
|
+
target = librarySaveTarget(config2, options.key);
|
|
59707
|
+
} catch (error62) {
|
|
59708
|
+
const refusal = refusalOf(error62);
|
|
59709
|
+
if (!refusal) throw error62;
|
|
59710
|
+
io.err(refusal.line);
|
|
59711
|
+
finish(refusal.code);
|
|
59712
|
+
return;
|
|
59713
|
+
}
|
|
59714
|
+
if (target.kind === "library" && (!options.input || options.input.length === 0)) {
|
|
58421
59715
|
io.err("zaku library save needs --input, the variables use_figma returned for zaku library script");
|
|
58422
59716
|
finish(3);
|
|
58423
59717
|
return;
|
|
@@ -58427,23 +59721,37 @@ var libraryCommand = (program2, io, finish, cli) => {
|
|
|
58427
59721
|
finish(3);
|
|
58428
59722
|
return;
|
|
58429
59723
|
}
|
|
58430
|
-
const part = mergeParts(
|
|
59724
|
+
const part = target.kind === "library" ? mergeParts(
|
|
58431
59725
|
await Promise.all(
|
|
58432
|
-
options.input.map(
|
|
58433
|
-
async (input2) => parseDesignFile(input2, await
|
|
59726
|
+
(options.input ?? []).map(
|
|
59727
|
+
async (input2) => parseDesignFile(input2, await readFile6(resolve2(io.cwd, input2), "utf8"), variablePartSchema)
|
|
58434
59728
|
)
|
|
58435
59729
|
)
|
|
58436
|
-
);
|
|
59730
|
+
) : void 0;
|
|
58437
59731
|
try {
|
|
58438
|
-
const
|
|
59732
|
+
const saved = await cli.bus.send(
|
|
59733
|
+
new SaveLibrary({
|
|
59734
|
+
root,
|
|
59735
|
+
...options.key !== void 0 ? { key: options.key } : {},
|
|
59736
|
+
...part ? { part } : {}
|
|
59737
|
+
})
|
|
59738
|
+
);
|
|
59739
|
+
if (saved.kind === "kit") {
|
|
59740
|
+
io.out(`wrote ${saved.dir}/kit.json: ${saved.kit.components.length} components`);
|
|
59741
|
+
finish(0);
|
|
59742
|
+
return;
|
|
59743
|
+
}
|
|
59744
|
+
const { snapshot, written, unchanged, removed } = saved;
|
|
58439
59745
|
if (snapshot.components.length === 0) {
|
|
58440
59746
|
io.err(
|
|
58441
|
-
|
|
59747
|
+
`${saved.dir}/ holds no components: the file publishes none and the export listed none; for a library in the product file, run zaku library script --local`
|
|
58442
59748
|
);
|
|
58443
59749
|
finish(1);
|
|
58444
59750
|
return;
|
|
58445
59751
|
}
|
|
58446
|
-
io.out(
|
|
59752
|
+
io.out(
|
|
59753
|
+
`wrote ${saved.dir}/: ${snapshot.components.length} components at version ${snapshot.version}; ${written.length} component files written, ${unchanged} unchanged, ${removed.length} removed`
|
|
59754
|
+
);
|
|
58447
59755
|
finish(0);
|
|
58448
59756
|
} finally {
|
|
58449
59757
|
await recordRestCalls(cli, io);
|
|
@@ -58452,7 +59760,7 @@ var libraryCommand = (program2, io, finish, cli) => {
|
|
|
58452
59760
|
};
|
|
58453
59761
|
var rulesCommand = (program2, io, finish) => {
|
|
58454
59762
|
const rules = program2.command("rules").description("zaku's rule checks, for a run that reaches Figma through use_figma");
|
|
58455
|
-
rules.command("script").description("print the Plugin API code that runs the rules over a page or a node, for use_figma").option("--root <dir>", "the design directory", "docs/design").option("--page <page>", "the page to check, by id or name").option("--node <id>", "the node to check, with everything inside it").option("--after <write.js>", "run this use_figma write first, then the rules, and answer both").action(async (options) => {
|
|
59763
|
+
rules.command("script").description("print the Plugin API code that runs the rules over a page or a node, for use_figma").option("--root <dir>", "the design directory", "docs/design").option("--page <page>", "the page to check, by id or name").option("--node <id>", "the node to check, with everything inside it").option("--after <write.js>", "run this use_figma write first, then the rules, and answer both").option("--key <key>", "the library file the page is in, so its views are held to the branches it holds").action(async (options) => {
|
|
58456
59764
|
if (options.page === void 0 === (options.node === void 0)) {
|
|
58457
59765
|
io.err("zaku rules script needs --page or --node, one of them");
|
|
58458
59766
|
finish(3);
|
|
@@ -58460,7 +59768,17 @@ var rulesCommand = (program2, io, finish) => {
|
|
|
58460
59768
|
}
|
|
58461
59769
|
const config2 = await readDesignFile(designPaths(resolve2(io.cwd, options.root)).config, zakuConfigSchema);
|
|
58462
59770
|
const scope = options.node !== void 0 ? { nodeId: options.node } : { page: options.page };
|
|
58463
|
-
const
|
|
59771
|
+
const graph = designGraph(config2);
|
|
59772
|
+
const file2 = options.key === void 0 ? graph.libraries.length === 1 ? graph.libraries[0] : void 0 : graph.libraries.find((library2) => library2.key === options.key);
|
|
59773
|
+
if (options.key !== void 0 && !file2) {
|
|
59774
|
+
io.err(
|
|
59775
|
+
`zaku rules script: ${options.key} is not a library zaku.yaml lists; name one with --key: ${graph.libraries.map((library2) => library2.key).join(", ")}`
|
|
59776
|
+
);
|
|
59777
|
+
finish(3);
|
|
59778
|
+
return;
|
|
59779
|
+
}
|
|
59780
|
+
const branches = file2?.branches ?? [];
|
|
59781
|
+
const check2 = `await zakuRulesLib.zakuRules(figma, ${JSON.stringify({ scope, copy: resolveCopy(config2.copy), ...branches.length > 1 ? { branches } : {} })})`;
|
|
58464
59782
|
const library = await runners.rulesLibrary();
|
|
58465
59783
|
if (options.after === void 0) {
|
|
58466
59784
|
io.out(`${library}
|
|
@@ -58468,11 +59786,11 @@ return ${check2};`);
|
|
|
58468
59786
|
finish(0);
|
|
58469
59787
|
return;
|
|
58470
59788
|
}
|
|
58471
|
-
const
|
|
59789
|
+
const write2 = await readFile6(resolve2(io.cwd, options.after), "utf8");
|
|
58472
59790
|
const body = [
|
|
58473
59791
|
library,
|
|
58474
59792
|
`const zakuWrite = async () => {
|
|
58475
|
-
${
|
|
59793
|
+
${write2}
|
|
58476
59794
|
};`,
|
|
58477
59795
|
"const zakuValue = await zakuWrite();",
|
|
58478
59796
|
"const value = zakuValue === undefined ? null : zakuValue;",
|
|
@@ -58499,6 +59817,7 @@ var COMMANDS = [
|
|
|
58499
59817
|
recipeCommand,
|
|
58500
59818
|
budgetCommand,
|
|
58501
59819
|
schemaCommand,
|
|
59820
|
+
librariesCommand,
|
|
58502
59821
|
mcpCommand
|
|
58503
59822
|
];
|
|
58504
59823
|
async function main(argv, io) {
|