@zeroxsolutions/zaku 0.0.3 → 0.1.0
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 +1266 -209
- package/package.json +3 -3
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) {
|
|
@@ -20681,7 +20681,7 @@ var import_reflect_metadata3 = __toESM(require_Reflect(), 1);
|
|
|
20681
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
|
|
@@ -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
|
|
|
@@ -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() {
|
|
@@ -44611,12 +44627,99 @@ WriteRecipeHandler = __decorate2([
|
|
|
44611
44627
|
|
|
44612
44628
|
// packages/zaku/dist/lib/handlers/save-library.js
|
|
44613
44629
|
var import_tsyringe3 = __toESM(require_cjs(), 1);
|
|
44630
|
+
import { relative as relative2 } from "node:path";
|
|
44614
44631
|
|
|
44615
44632
|
// packages/zaku/dist/lib/domain/copy-defaults.js
|
|
44616
44633
|
var DEFAULT_COPY = { locales: ["en"], currencies: [] };
|
|
44617
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
|
+
var branchOf = (target) => target.branch ?? defaultBranch(target.family);
|
|
44643
|
+
var unique = (values) => [...new Set(values)];
|
|
44644
|
+
function legacyFiles(config2) {
|
|
44645
|
+
const branches = unique(config2.targets.flatMap((target) => branchOf(target) ?? []));
|
|
44646
|
+
const families2 = unique(config2.targets.map((target) => target.family));
|
|
44647
|
+
const { library, product } = config2.figma;
|
|
44648
|
+
return {
|
|
44649
|
+
libraries: library === void 0 ? [] : [{ key: library, layer: "foundations", branches: branches.length > 0 ? branches : ["ui"], extends: [] }],
|
|
44650
|
+
products: product === void 0 ? [] : families2.map((family) => ({ key: product, family }))
|
|
44651
|
+
};
|
|
44652
|
+
}
|
|
44653
|
+
function designGraph(config2) {
|
|
44654
|
+
const { figma } = config2;
|
|
44655
|
+
const legacy = figma.library !== void 0 || figma.product !== void 0;
|
|
44656
|
+
const { libraries, products } = legacy ? legacyFiles(config2) : { libraries: figma.libraries ?? [], products: figma.products ?? [] };
|
|
44657
|
+
const kits = figma.kits ?? [];
|
|
44658
|
+
const prototypes = figma.prototypes ?? [];
|
|
44659
|
+
const byKey = new Map(libraries.map((library) => [library.key, library]));
|
|
44660
|
+
const closure = (key) => {
|
|
44661
|
+
const out = [];
|
|
44662
|
+
const visit2 = (next) => {
|
|
44663
|
+
if (out.includes(next))
|
|
44664
|
+
return;
|
|
44665
|
+
out.push(next);
|
|
44666
|
+
for (const base of byKey.get(next)?.extends ?? [])
|
|
44667
|
+
visit2(base);
|
|
44668
|
+
};
|
|
44669
|
+
visit2(key);
|
|
44670
|
+
return out;
|
|
44671
|
+
};
|
|
44672
|
+
return {
|
|
44673
|
+
libraries,
|
|
44674
|
+
kits,
|
|
44675
|
+
products,
|
|
44676
|
+
prototypes,
|
|
44677
|
+
legacy,
|
|
44678
|
+
branchOf,
|
|
44679
|
+
targetsOf: (family) => config2.targets.filter((target) => target.family === family),
|
|
44680
|
+
librariesFor: (target) => {
|
|
44681
|
+
if (legacy)
|
|
44682
|
+
return libraries;
|
|
44683
|
+
const branch = branchOf(target);
|
|
44684
|
+
return libraries.filter((library) => branch !== void 0 && library.branches.includes(branch));
|
|
44685
|
+
},
|
|
44686
|
+
kitsFor: (target) => kits.filter((kit) => kit.family === target.family),
|
|
44687
|
+
closure,
|
|
44688
|
+
multiBranch: (key) => (byKey.get(key)?.branches.length ?? 0) > 1,
|
|
44689
|
+
productOf: (prototypeKey) => {
|
|
44690
|
+
const prototype2 = prototypes.find((candidate) => candidate.key === prototypeKey);
|
|
44691
|
+
return products.find((product) => product.family === prototype2?.family)?.key;
|
|
44692
|
+
}
|
|
44693
|
+
};
|
|
44694
|
+
}
|
|
44695
|
+
function snapshotsFor(input2, target) {
|
|
44696
|
+
const graph = designGraph(input2.config);
|
|
44697
|
+
const branch = target ? graph.branchOf(target) : void 0;
|
|
44698
|
+
const missing = [];
|
|
44699
|
+
const libraries = (target ? graph.librariesFor(target) : graph.libraries).flatMap((library) => {
|
|
44700
|
+
const snapshot = input2.libraries[library.key];
|
|
44701
|
+
if (!snapshot) {
|
|
44702
|
+
missing.push(library.key);
|
|
44703
|
+
return [];
|
|
44704
|
+
}
|
|
44705
|
+
if (!target || !graph.multiBranch(library.key))
|
|
44706
|
+
return [snapshot];
|
|
44707
|
+
const components = snapshot.components.filter((component2) => component2.branch === void 0 || component2.branch === branch);
|
|
44708
|
+
return [{ ...snapshot, components }];
|
|
44709
|
+
});
|
|
44710
|
+
const kits = (target ? graph.kitsFor(target) : graph.kits).flatMap((kit) => {
|
|
44711
|
+
const snapshot = input2.kits[kit.key];
|
|
44712
|
+
if (!snapshot)
|
|
44713
|
+
missing.push(kit.key);
|
|
44714
|
+
return snapshot ? [snapshot] : [];
|
|
44715
|
+
});
|
|
44716
|
+
return { libraries, kits, missing };
|
|
44717
|
+
}
|
|
44718
|
+
|
|
44618
44719
|
// packages/zaku/dist/lib/schema/zaku-config.js
|
|
44619
44720
|
var PLATFORM_FAMILIES = ["web", "ios", "android", "macos", "windows", "gnome", "kde"];
|
|
44721
|
+
var LAYERS = ["foundations", "components"];
|
|
44722
|
+
var BRANCHES = ["ui", "native"];
|
|
44620
44723
|
var DEFAULT_INTERACTIVE = [
|
|
44621
44724
|
"Button",
|
|
44622
44725
|
"Button Group",
|
|
@@ -44643,7 +44746,9 @@ var targetSchema = external_exports.object({
|
|
|
44643
44746
|
family: external_exports.enum(PLATFORM_FAMILIES),
|
|
44644
44747
|
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"),
|
|
44645
44748
|
/** The frame size every frame of this target is drawn at; the frame check compares it. */
|
|
44646
|
-
size: external_exports.object({ width: external_exports.number().positive(), height: external_exports.number().positive() }).strict().optional()
|
|
44749
|
+
size: external_exports.object({ width: external_exports.number().positive(), height: external_exports.number().positive() }).strict().optional(),
|
|
44750
|
+
/** The renderer whose libraries its frames draw from; `defaultBranch` in the design graph gives it when left out. */
|
|
44751
|
+
branch: external_exports.enum(BRANCHES).optional()
|
|
44647
44752
|
}).strict();
|
|
44648
44753
|
var DEFAULT_SYSTEM_BARS = {
|
|
44649
44754
|
web: [],
|
|
@@ -44663,7 +44768,28 @@ var budgetSchema = external_exports.object({
|
|
|
44663
44768
|
mcpPerRun: external_exports.number().int().positive().default(30),
|
|
44664
44769
|
reserve: external_exports.number().min(0).max(1).default(0.2)
|
|
44665
44770
|
}).strict();
|
|
44666
|
-
var
|
|
44771
|
+
var fileKey = external_exports.string().min(1);
|
|
44772
|
+
var kitSchema = external_exports.object({ key: fileKey, family: external_exports.enum(PLATFORM_FAMILIES) }).strict();
|
|
44773
|
+
var librarySchema = external_exports.object({
|
|
44774
|
+
key: fileKey,
|
|
44775
|
+
layer: external_exports.enum(LAYERS),
|
|
44776
|
+
branches: external_exports.array(external_exports.enum(BRANCHES)).min(1),
|
|
44777
|
+
/** The libraries and kits this one is built on, by key. */
|
|
44778
|
+
extends: external_exports.array(fileKey).default([])
|
|
44779
|
+
}).strict();
|
|
44780
|
+
var productSchema = external_exports.object({ key: fileKey, family: external_exports.enum(PLATFORM_FAMILIES) }).strict();
|
|
44781
|
+
var prototypeSchema = external_exports.object({ key: fileKey, family: external_exports.enum(PLATFORM_FAMILIES) }).strict();
|
|
44782
|
+
var files = external_exports.object({
|
|
44783
|
+
library: fileKey.optional(),
|
|
44784
|
+
product: fileKey.optional(),
|
|
44785
|
+
kits: external_exports.array(kitSchema).optional(),
|
|
44786
|
+
libraries: external_exports.array(librarySchema).optional(),
|
|
44787
|
+
products: external_exports.array(productSchema).optional(),
|
|
44788
|
+
prototypes: external_exports.array(prototypeSchema).optional()
|
|
44789
|
+
}).strict();
|
|
44790
|
+
function byRole(figma) {
|
|
44791
|
+
return [figma.kits, figma.libraries, figma.products, figma.prototypes].some((list) => list !== void 0);
|
|
44792
|
+
}
|
|
44667
44793
|
var shadcnSystem = external_exports.object({ preset: external_exports.string().min(1) }).strict();
|
|
44668
44794
|
var tokenFiles = external_exports.array(external_exports.string().min(1)).min(1);
|
|
44669
44795
|
var resolverInputs = external_exports.record(external_exports.string(), external_exports.string());
|
|
@@ -44715,7 +44841,7 @@ var copySchema = external_exports.object({
|
|
|
44715
44841
|
locales: external_exports.array(external_exports.string().refine(writtenInAScript, "a BCP 47 language tag, such as en or vi")).min(1).default(["en"]),
|
|
44716
44842
|
currencies: external_exports.array(external_exports.string().refine((code) => Intl.supportedValuesOf("currency").includes(code), "an ISO 4217 code, such as VND or USD")).default([])
|
|
44717
44843
|
}).strict();
|
|
44718
|
-
var
|
|
44844
|
+
var configShape = external_exports.object({
|
|
44719
44845
|
product: external_exports.string().min(1),
|
|
44720
44846
|
designSystem: designSystemSchema,
|
|
44721
44847
|
figma: files.default({}),
|
|
@@ -44727,7 +44853,8 @@ var zakuConfigSchema = external_exports.object({
|
|
|
44727
44853
|
budget: budgetSchema.default({ mcpPerDay: 200, mcpPerRun: 30, reserve: 0.2 }),
|
|
44728
44854
|
recipe: recipeSchema.optional(),
|
|
44729
44855
|
copy: copySchema.default(DEFAULT_COPY)
|
|
44730
|
-
}).strict()
|
|
44856
|
+
}).strict();
|
|
44857
|
+
var zakuConfigSchema = configShape.superRefine((config2, ctx) => {
|
|
44731
44858
|
for (const key of ["id", "name"]) {
|
|
44732
44859
|
const seen = /* @__PURE__ */ new Set();
|
|
44733
44860
|
config2.targets.forEach((target, index) => {
|
|
@@ -44741,7 +44868,117 @@ var zakuConfigSchema = external_exports.object({
|
|
|
44741
44868
|
seen.add(target[key]);
|
|
44742
44869
|
});
|
|
44743
44870
|
}
|
|
44871
|
+
if (byRole(config2.figma))
|
|
44872
|
+
refineFilesByRole(config2, ctx);
|
|
44744
44873
|
});
|
|
44874
|
+
function refineFilesByRole(config2, ctx) {
|
|
44875
|
+
const { figma } = config2;
|
|
44876
|
+
if (figma.library !== void 0 || figma.product !== void 0) {
|
|
44877
|
+
ctx.addIssue({
|
|
44878
|
+
code: "custom",
|
|
44879
|
+
path: ["figma"],
|
|
44880
|
+
message: "figma.library and figma.product describe one library and one product; list files by role instead"
|
|
44881
|
+
});
|
|
44882
|
+
}
|
|
44883
|
+
const kits = figma.kits ?? [];
|
|
44884
|
+
const libraries = figma.libraries ?? [];
|
|
44885
|
+
const products = figma.products ?? [];
|
|
44886
|
+
const seen = /* @__PURE__ */ new Set();
|
|
44887
|
+
const lists = [
|
|
44888
|
+
["kits", kits],
|
|
44889
|
+
["libraries", libraries],
|
|
44890
|
+
["products", products],
|
|
44891
|
+
["prototypes", figma.prototypes ?? []]
|
|
44892
|
+
];
|
|
44893
|
+
for (const [list, entries] of lists) {
|
|
44894
|
+
entries.forEach((entry, index) => {
|
|
44895
|
+
if (seen.has(entry.key))
|
|
44896
|
+
ctx.addIssue({
|
|
44897
|
+
code: "custom",
|
|
44898
|
+
path: ["figma", list, index, "key"],
|
|
44899
|
+
message: `a second file with key ${entry.key}`
|
|
44900
|
+
});
|
|
44901
|
+
seen.add(entry.key);
|
|
44902
|
+
});
|
|
44903
|
+
}
|
|
44904
|
+
const byKey = new Map(libraries.map((library) => [library.key, library]));
|
|
44905
|
+
const kitKeys = new Set(kits.map((kit) => kit.key));
|
|
44906
|
+
libraries.forEach((library, index) => {
|
|
44907
|
+
const path2 = ["figma", "libraries", index, "extends"];
|
|
44908
|
+
for (const key of library.extends) {
|
|
44909
|
+
const base = byKey.get(key);
|
|
44910
|
+
if (!base && !kitKeys.has(key)) {
|
|
44911
|
+
ctx.addIssue({
|
|
44912
|
+
code: "custom",
|
|
44913
|
+
path: path2,
|
|
44914
|
+
message: `${library.key} extends ${key}, which is no library or kit listed`
|
|
44915
|
+
});
|
|
44916
|
+
} else if (base?.layer === "components" && library.layer === "foundations") {
|
|
44917
|
+
ctx.addIssue({ code: "custom", path: path2, message: `foundations ${library.key} extends components ${key}` });
|
|
44918
|
+
} else if (base && !base.branches.some((branch) => library.branches.includes(branch))) {
|
|
44919
|
+
ctx.addIssue({
|
|
44920
|
+
code: "custom",
|
|
44921
|
+
path: path2,
|
|
44922
|
+
message: `${library.key} extends ${key}, which holds none of its branches`
|
|
44923
|
+
});
|
|
44924
|
+
}
|
|
44925
|
+
}
|
|
44926
|
+
});
|
|
44927
|
+
const cycle = findCycle(libraries);
|
|
44928
|
+
if (cycle)
|
|
44929
|
+
ctx.addIssue({ code: "custom", path: ["figma", "libraries"], message: `extends comes back: ${cycle}` });
|
|
44930
|
+
for (const [list, entries] of [
|
|
44931
|
+
["products", products],
|
|
44932
|
+
["prototypes", figma.prototypes ?? []]
|
|
44933
|
+
]) {
|
|
44934
|
+
const families2 = /* @__PURE__ */ new Set();
|
|
44935
|
+
entries.forEach((entry, index) => {
|
|
44936
|
+
if (families2.has(entry.family))
|
|
44937
|
+
ctx.addIssue({
|
|
44938
|
+
code: "custom",
|
|
44939
|
+
path: ["figma", list, index, "family"],
|
|
44940
|
+
message: `a second ${list === "products" ? "product" : "prototype"} file for ${entry.family}`
|
|
44941
|
+
});
|
|
44942
|
+
families2.add(entry.family);
|
|
44943
|
+
});
|
|
44944
|
+
}
|
|
44945
|
+
(figma.prototypes ?? []).forEach((prototype2, index) => {
|
|
44946
|
+
if (!products.some((product) => product.family === prototype2.family))
|
|
44947
|
+
ctx.addIssue({
|
|
44948
|
+
code: "custom",
|
|
44949
|
+
path: ["figma", "prototypes", index, "family"],
|
|
44950
|
+
message: `no product file for ${prototype2.family} to copy its frames from`
|
|
44951
|
+
});
|
|
44952
|
+
});
|
|
44953
|
+
config2.targets.forEach((target, index) => {
|
|
44954
|
+
const branch = target.branch ?? defaultBranch(target.family);
|
|
44955
|
+
const path2 = ["targets", index, "branch"];
|
|
44956
|
+
if (branch === void 0) {
|
|
44957
|
+
ctx.addIssue({ code: "custom", path: path2, message: `a ${target.family} target names its branch, ui or native` });
|
|
44958
|
+
} else if (libraries.length > 0 && !libraries.some((library) => library.branches.includes(branch))) {
|
|
44959
|
+
ctx.addIssue({ code: "custom", path: path2, message: `no library holds the ${branch} branch` });
|
|
44960
|
+
}
|
|
44961
|
+
});
|
|
44962
|
+
}
|
|
44963
|
+
function findCycle(libraries) {
|
|
44964
|
+
const byKey = new Map(libraries.map((library) => [library.key, library]));
|
|
44965
|
+
const visit2 = (key, path2) => {
|
|
44966
|
+
if (path2.includes(key))
|
|
44967
|
+
return [...path2.slice(path2.indexOf(key)), key].join(" -> ");
|
|
44968
|
+
for (const next of byKey.get(key)?.extends ?? []) {
|
|
44969
|
+
const found = visit2(next, [...path2, key]);
|
|
44970
|
+
if (found)
|
|
44971
|
+
return found;
|
|
44972
|
+
}
|
|
44973
|
+
return void 0;
|
|
44974
|
+
};
|
|
44975
|
+
for (const library of libraries) {
|
|
44976
|
+
const found = visit2(library.key, []);
|
|
44977
|
+
if (found)
|
|
44978
|
+
return found;
|
|
44979
|
+
}
|
|
44980
|
+
return void 0;
|
|
44981
|
+
}
|
|
44745
44982
|
|
|
44746
44983
|
// packages/zaku/dist/lib/repositories/design-file.js
|
|
44747
44984
|
var import_yaml = __toESM(require_dist(), 1);
|
|
@@ -44782,6 +45019,12 @@ async function writeDesignFile(path2, value) {
|
|
|
44782
45019
|
|
|
44783
45020
|
// packages/zaku/dist/lib/repositories/design-paths.js
|
|
44784
45021
|
import { join as join2 } from "node:path";
|
|
45022
|
+
function librarySnapshotDir(paths, key) {
|
|
45023
|
+
if (key === null)
|
|
45024
|
+
return paths;
|
|
45025
|
+
const library = join2(paths.library, key);
|
|
45026
|
+
return { root: paths.root, library, libraryIndex: join2(library, "index.json"), legacyLibrary: null };
|
|
45027
|
+
}
|
|
44785
45028
|
function designPaths(root) {
|
|
44786
45029
|
return {
|
|
44787
45030
|
root,
|
|
@@ -44825,8 +45068,13 @@ var libraryItemSchema = external_exports.object({
|
|
|
44825
45068
|
fontFamily: external_exports.string().nullable(),
|
|
44826
45069
|
textStyleKey: external_exports.string().nullable(),
|
|
44827
45070
|
componentKey: external_exports.string().nullable(),
|
|
44828
|
-
bindings: external_exports.record(external_exports.string(), external_exports.string().nullable())
|
|
45071
|
+
bindings: external_exports.record(external_exports.string(), external_exports.string().nullable()),
|
|
45072
|
+
/** Every variable the layer's own properties are bound to, by id without its `VariableID:` prefix. */
|
|
45073
|
+
variableIds: external_exports.array(external_exports.string()).optional(),
|
|
45074
|
+
effectStyleKey: external_exports.string().optional()
|
|
44829
45075
|
}).strict();
|
|
45076
|
+
var variableKeySchema = external_exports.object({ key: external_exports.string(), local: external_exports.boolean() }).strict();
|
|
45077
|
+
var effectStyleSchema = external_exports.object({ key: external_exports.string(), name: external_exports.string() }).strict();
|
|
44830
45078
|
var libraryVariantSchema = external_exports.object({
|
|
44831
45079
|
key: external_exports.string(),
|
|
44832
45080
|
name: external_exports.string(),
|
|
@@ -44837,6 +45085,8 @@ var libraryComponentSchema = external_exports.object({
|
|
|
44837
45085
|
name: external_exports.string(),
|
|
44838
45086
|
key: external_exports.string(),
|
|
44839
45087
|
page: external_exports.string(),
|
|
45088
|
+
/** The branch of the view that holds it, in a file that holds several; none where it serves every branch. */
|
|
45089
|
+
branch: external_exports.string().optional(),
|
|
44840
45090
|
codePath: external_exports.string().nullable(),
|
|
44841
45091
|
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(),
|
|
44842
45092
|
variants: external_exports.array(libraryVariantSchema).min(1)
|
|
@@ -44856,12 +45106,22 @@ var libraryPartSchema = external_exports.object({
|
|
|
44856
45106
|
exportedAt: external_exports.string(),
|
|
44857
45107
|
components: external_exports.array(libraryComponentSchema),
|
|
44858
45108
|
textStyles: external_exports.array(textStyleSchema),
|
|
44859
|
-
tokens: external_exports.array(tokenSnapshotSchema)
|
|
45109
|
+
tokens: external_exports.array(tokenSnapshotSchema),
|
|
45110
|
+
/**
|
|
45111
|
+
* What the items' references resolve against, absent from a snapshot saved before they were recorded: each
|
|
45112
|
+
* variable id's key, the file's effect styles, and the keys of the components the file holds unpublished.
|
|
45113
|
+
*/
|
|
45114
|
+
variableKeys: external_exports.record(external_exports.string(), variableKeySchema).optional(),
|
|
45115
|
+
effectStyles: external_exports.array(effectStyleSchema).optional(),
|
|
45116
|
+
localComponents: external_exports.array(external_exports.string()).optional()
|
|
44860
45117
|
}).strict();
|
|
44861
45118
|
var variablePartSchema = external_exports.object({
|
|
44862
45119
|
exportedAt: external_exports.string(),
|
|
44863
45120
|
variables: external_exports.record(external_exports.string(), external_exports.string()),
|
|
44864
45121
|
textStyles: external_exports.array(textStyleSchema),
|
|
45122
|
+
/** Each variable's key, keyed like `variables`. */
|
|
45123
|
+
variableKeys: external_exports.record(external_exports.string(), variableKeySchema).optional(),
|
|
45124
|
+
effectStyles: external_exports.array(effectStyleSchema).optional(),
|
|
44865
45125
|
tokens: external_exports.array(external_exports.object({
|
|
44866
45126
|
combo: external_exports.record(external_exports.string(), external_exports.string()),
|
|
44867
45127
|
values: external_exports.record(external_exports.string(), external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean()]))
|
|
@@ -44872,10 +45132,17 @@ var variablePartSchema = external_exports.object({
|
|
|
44872
45132
|
key: external_exports.string(),
|
|
44873
45133
|
name: external_exports.string(),
|
|
44874
45134
|
page: external_exports.string(),
|
|
45135
|
+
/** The view that holds it: the frame directly on its page, where it sits in one. */
|
|
45136
|
+
frame: external_exports.string().optional(),
|
|
44875
45137
|
description: external_exports.string(),
|
|
44876
45138
|
set: external_exports.boolean()
|
|
44877
45139
|
}).strict()).optional()
|
|
44878
45140
|
}).strict();
|
|
45141
|
+
var kitSnapshotSchema = external_exports.object({
|
|
45142
|
+
key: external_exports.string(),
|
|
45143
|
+
family: external_exports.string(),
|
|
45144
|
+
components: external_exports.array(external_exports.object({ key: external_exports.string(), name: external_exports.string() }).strict())
|
|
45145
|
+
}).strict();
|
|
44879
45146
|
var librarySnapshotSchema = libraryPartSchema.extend({ source: external_exports.string(), version: external_exports.string() }).strict();
|
|
44880
45147
|
|
|
44881
45148
|
// packages/zaku/dist/lib/domain/library-files.js
|
|
@@ -44944,7 +45211,9 @@ function expandItem(stored, values) {
|
|
|
44944
45211
|
fontFamily: stored.fontFamily ?? null,
|
|
44945
45212
|
textStyleKey: stored.textStyleKey ?? null,
|
|
44946
45213
|
componentKey: stored.componentKey ?? null,
|
|
44947
|
-
bindings
|
|
45214
|
+
bindings,
|
|
45215
|
+
...stored.variableIds ? { variableIds: stored.variableIds } : {},
|
|
45216
|
+
...stored.effectStyleKey ? { effectStyleKey: stored.effectStyleKey } : {}
|
|
44948
45217
|
};
|
|
44949
45218
|
}
|
|
44950
45219
|
function compactItem(item, values) {
|
|
@@ -44960,6 +45229,10 @@ function compactItem(item, values) {
|
|
|
44960
45229
|
stored[field] = item[field];
|
|
44961
45230
|
if (item.glyph)
|
|
44962
45231
|
stored["glyph"] = item.glyph;
|
|
45232
|
+
if (item.variableIds)
|
|
45233
|
+
stored["variableIds"] = item.variableIds;
|
|
45234
|
+
if (item.effectStyleKey)
|
|
45235
|
+
stored["effectStyleKey"] = item.effectStyleKey;
|
|
44963
45236
|
const bindings = Object.fromEntries(Object.entries(item.bindings).filter(([name, value]) => value !== null || name === "glyph"));
|
|
44964
45237
|
if (Object.keys(bindings).length > 0)
|
|
44965
45238
|
stored["bindings"] = bindings;
|
|
@@ -45077,7 +45350,7 @@ async function writeText(path2, text) {
|
|
|
45077
45350
|
async function readLibrarySnapshot(paths) {
|
|
45078
45351
|
const index = await readOptionalDesignFile(paths.libraryIndex, libraryIndexSchema);
|
|
45079
45352
|
if (!index)
|
|
45080
|
-
return readOptionalDesignFile(paths.legacyLibrary, librarySnapshotSchema);
|
|
45353
|
+
return paths.legacyLibrary ? readOptionalDesignFile(paths.legacyLibrary, librarySnapshotSchema) : null;
|
|
45081
45354
|
const files2 = /* @__PURE__ */ new Map();
|
|
45082
45355
|
for (const component2 of index.components) {
|
|
45083
45356
|
const path2 = join3(paths.library, component2.file);
|
|
@@ -45118,12 +45391,49 @@ async function writeLibrarySnapshot(paths, snapshot) {
|
|
|
45118
45391
|
removed.push(file2);
|
|
45119
45392
|
}
|
|
45120
45393
|
await writeText(paths.libraryIndex, formatLibraryFile(index));
|
|
45121
|
-
if (await readText(paths.legacyLibrary) !== null) {
|
|
45394
|
+
if (paths.legacyLibrary && await readText(paths.legacyLibrary) !== null) {
|
|
45122
45395
|
await rm(paths.legacyLibrary);
|
|
45123
45396
|
removed.push(relative(paths.root, paths.legacyLibrary));
|
|
45124
45397
|
}
|
|
45125
45398
|
return { written, unchanged, removed };
|
|
45126
45399
|
}
|
|
45400
|
+
async function writeKitSnapshot(paths, kit) {
|
|
45401
|
+
await mkdir(paths.library, { recursive: true });
|
|
45402
|
+
const path2 = join3(paths.library, "kit.json");
|
|
45403
|
+
await writeText(path2, formatLibraryFile(kit));
|
|
45404
|
+
return path2;
|
|
45405
|
+
}
|
|
45406
|
+
async function readDesignSnapshots(paths, config2) {
|
|
45407
|
+
const graph = designGraph(config2);
|
|
45408
|
+
const libraries = {};
|
|
45409
|
+
const kits = {};
|
|
45410
|
+
const errors = [];
|
|
45411
|
+
const attempt = async (read) => {
|
|
45412
|
+
try {
|
|
45413
|
+
await read();
|
|
45414
|
+
} catch (error62) {
|
|
45415
|
+
if (!(error62 instanceof DesignFileInvalid))
|
|
45416
|
+
throw error62;
|
|
45417
|
+
errors.push(error62);
|
|
45418
|
+
}
|
|
45419
|
+
};
|
|
45420
|
+
for (const library of graph.libraries) {
|
|
45421
|
+
await attempt(async () => {
|
|
45422
|
+
const snapshot = await readLibrarySnapshot(librarySnapshotDir(paths, graph.legacy ? null : library.key));
|
|
45423
|
+
if (snapshot)
|
|
45424
|
+
libraries[library.key] = snapshot;
|
|
45425
|
+
});
|
|
45426
|
+
}
|
|
45427
|
+
for (const kit of graph.kits) {
|
|
45428
|
+
await attempt(async () => {
|
|
45429
|
+
const path2 = join3(librarySnapshotDir(paths, kit.key).library, "kit.json");
|
|
45430
|
+
const snapshot = await readOptionalDesignFile(path2, kitSnapshotSchema);
|
|
45431
|
+
if (snapshot)
|
|
45432
|
+
kits[kit.key] = snapshot;
|
|
45433
|
+
});
|
|
45434
|
+
}
|
|
45435
|
+
return { libraries, kits, errors };
|
|
45436
|
+
}
|
|
45127
45437
|
|
|
45128
45438
|
// packages/zaku/dist/lib/adapters/figma-rest-library.js
|
|
45129
45439
|
var DOCUMENTATION_PREFIXES = ["DS/"];
|
|
@@ -45197,6 +45507,23 @@ function strokeWeightsOf(node2) {
|
|
|
45197
45507
|
const weight = node2.strokeWeight ?? 0;
|
|
45198
45508
|
return [weight, weight, weight, weight];
|
|
45199
45509
|
}
|
|
45510
|
+
function aliasIds(node2) {
|
|
45511
|
+
const out = [];
|
|
45512
|
+
const visit2 = (value) => {
|
|
45513
|
+
if (Array.isArray(value))
|
|
45514
|
+
value.forEach(visit2);
|
|
45515
|
+
else if (value && typeof value === "object") {
|
|
45516
|
+
if ("id" in value && typeof value.id === "string")
|
|
45517
|
+
out.push(value.id.replace(/^VariableID:/, ""));
|
|
45518
|
+
else
|
|
45519
|
+
Object.values(value).forEach(visit2);
|
|
45520
|
+
}
|
|
45521
|
+
};
|
|
45522
|
+
visit2(node2.boundVariables);
|
|
45523
|
+
for (const paint of [...node2.fills ?? [], ...node2.strokes ?? []])
|
|
45524
|
+
visit2(paint.boundVariables);
|
|
45525
|
+
return [...new Set(out)];
|
|
45526
|
+
}
|
|
45200
45527
|
var GLYPH_TYPES = /* @__PURE__ */ new Set(["VECTOR", "BOOLEAN_OPERATION", "LINE", "ELLIPSE", "POLYGON", "STAR"]);
|
|
45201
45528
|
function glyphOf(instance, at) {
|
|
45202
45529
|
let text = false;
|
|
@@ -45236,6 +45563,9 @@ function itemsOf(root, at) {
|
|
|
45236
45563
|
const textStyle = node2.styles?.["text"];
|
|
45237
45564
|
const glyph = path2 !== "" && node2.type === "INSTANCE" ? glyphOf(node2, at) : null;
|
|
45238
45565
|
const componentId = node2.type === "INSTANCE" ? node2.componentId : path2 === "" ? node2.id : void 0;
|
|
45566
|
+
const variableIds = aliasIds(node2);
|
|
45567
|
+
const effectStyle = node2.styles?.["effect"];
|
|
45568
|
+
const effectStyleKey = effectStyle ? at.entry.styles[effectStyle]?.key : void 0;
|
|
45239
45569
|
out.push({
|
|
45240
45570
|
nodeId: node2.id,
|
|
45241
45571
|
path: path2,
|
|
@@ -45260,7 +45590,9 @@ function itemsOf(root, at) {
|
|
|
45260
45590
|
textColor: isText ? fill.binding : null,
|
|
45261
45591
|
radius: radiusName,
|
|
45262
45592
|
...glyph?.value ? { glyph: glyph.binding } : {}
|
|
45263
|
-
}
|
|
45593
|
+
},
|
|
45594
|
+
...variableIds.length > 0 ? { variableIds } : {},
|
|
45595
|
+
...effectStyleKey ? { effectStyleKey } : {}
|
|
45264
45596
|
});
|
|
45265
45597
|
if (path2 === "" || node2.type !== "INSTANCE") {
|
|
45266
45598
|
for (const child of node2.children ?? [])
|
|
@@ -45279,28 +45611,55 @@ function asPublished(component2) {
|
|
|
45279
45611
|
containing_frame: { pageName: component2.page }
|
|
45280
45612
|
};
|
|
45281
45613
|
}
|
|
45614
|
+
function viewBranch(view, branches) {
|
|
45615
|
+
const prefix = view?.split(" / ")[0];
|
|
45616
|
+
return view?.includes(" / ") && prefix !== void 0 && branches.includes(prefix) ? prefix : void 0;
|
|
45617
|
+
}
|
|
45618
|
+
function viewsByPage(document) {
|
|
45619
|
+
return new Map((document.children ?? []).map((page) => [
|
|
45620
|
+
page.name,
|
|
45621
|
+
(page.children ?? []).flatMap((view) => view.absoluteBoundingBox ? [{ name: view.name, box: view.absoluteBoundingBox }] : [])
|
|
45622
|
+
]));
|
|
45623
|
+
}
|
|
45624
|
+
function viewHolding(views, box) {
|
|
45625
|
+
if (!box)
|
|
45626
|
+
return void 0;
|
|
45627
|
+
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;
|
|
45628
|
+
}
|
|
45282
45629
|
async function readLibrary(options) {
|
|
45283
|
-
const { rest, fileKey:
|
|
45630
|
+
const { rest, fileKey: fileKey3, part } = options;
|
|
45631
|
+
const branches = options.branches ?? [];
|
|
45632
|
+
const multiBranch = branches.length > 1;
|
|
45633
|
+
const exported = new Map((part.components ?? []).map((component2) => [component2.id, component2.frame]));
|
|
45284
45634
|
const listed = part.components ? {
|
|
45285
45635
|
sets: part.components.filter((component2) => component2.set).map(asPublished),
|
|
45286
45636
|
components: part.components.filter((component2) => !component2.set).map(asPublished)
|
|
45287
|
-
} : await rest.published(
|
|
45637
|
+
} : await rest.published(fileKey3);
|
|
45288
45638
|
const published = [
|
|
45289
45639
|
...listed.sets,
|
|
45290
45640
|
...listed.components.filter((component2) => !component2.containing_frame?.containingComponentSet)
|
|
45291
45641
|
].filter((meta3) => !DOCUMENTATION_PREFIXES.some((prefix) => meta3.name.startsWith(prefix)));
|
|
45292
|
-
const file2 = await rest.file(
|
|
45293
|
-
const
|
|
45642
|
+
const file2 = await rest.file(fileKey3, multiBranch ? 2 : 1);
|
|
45643
|
+
const views = multiBranch ? viewsByPage(file2.document) : /* @__PURE__ */ new Map();
|
|
45644
|
+
const response = published.length > 0 ? await rest.nodes(fileKey3, published.map((meta3) => meta3.node_id)) : { version: file2.version, nodes: {} };
|
|
45294
45645
|
const components = [];
|
|
45646
|
+
const localComponents = /* @__PURE__ */ new Set();
|
|
45647
|
+
for (const entry of Object.values(response.nodes))
|
|
45648
|
+
for (const meta3 of Object.values(entry?.components ?? {}))
|
|
45649
|
+
if (meta3.remote === false)
|
|
45650
|
+
localComponents.add(meta3.key);
|
|
45295
45651
|
for (const meta3 of published) {
|
|
45296
45652
|
const entry = response.nodes[meta3.node_id];
|
|
45297
45653
|
if (!entry)
|
|
45298
45654
|
continue;
|
|
45299
45655
|
const variantNodes = entry.document.type === "COMPONENT_SET" ? (entry.document.children ?? []).filter((child) => child.type === "COMPONENT") : [entry.document];
|
|
45656
|
+
const view = exported.has(meta3.node_id) ? exported.get(meta3.node_id) : viewHolding(views.get(meta3.containing_frame?.pageName ?? "") ?? [], entry.document.absoluteBoundingBox);
|
|
45657
|
+
const branch = multiBranch ? viewBranch(view, branches) : void 0;
|
|
45300
45658
|
components.push({
|
|
45301
45659
|
name: meta3.name,
|
|
45302
45660
|
key: meta3.key,
|
|
45303
45661
|
page: (meta3.containing_frame?.pageName ?? "").replace(/^\W+\s*/, ""),
|
|
45662
|
+
...branch ? { branch } : {},
|
|
45304
45663
|
...descriptionMap(meta3.description),
|
|
45305
45664
|
variants: variantNodes.map((variant) => ({
|
|
45306
45665
|
key: entry.components[variant.id]?.key ?? "",
|
|
@@ -45314,11 +45673,16 @@ async function readLibrary(options) {
|
|
|
45314
45673
|
});
|
|
45315
45674
|
}
|
|
45316
45675
|
return {
|
|
45317
|
-
source:
|
|
45676
|
+
source: fileKey3,
|
|
45318
45677
|
version: file2.version,
|
|
45319
45678
|
exportedAt: part.exportedAt,
|
|
45320
45679
|
components,
|
|
45321
45680
|
textStyles: part.textStyles,
|
|
45681
|
+
...part.variableKeys ? {
|
|
45682
|
+
variableKeys: part.variableKeys,
|
|
45683
|
+
effectStyles: part.effectStyles ?? [],
|
|
45684
|
+
localComponents: [...localComponents].sort()
|
|
45685
|
+
} : {},
|
|
45322
45686
|
tokens: part.tokens.map((token) => ({
|
|
45323
45687
|
combo: token.combo,
|
|
45324
45688
|
values: Object.fromEntries(Object.entries(token.values).map(([name, value]) => [
|
|
@@ -45328,16 +45692,57 @@ async function readLibrary(options) {
|
|
|
45328
45692
|
}))
|
|
45329
45693
|
};
|
|
45330
45694
|
}
|
|
45695
|
+
async function readKit(options) {
|
|
45696
|
+
const components = await options.rest.components(options.key);
|
|
45697
|
+
return {
|
|
45698
|
+
key: options.key,
|
|
45699
|
+
family: options.family,
|
|
45700
|
+
components: components.map((component2) => ({ key: component2.key, name: component2.name }))
|
|
45701
|
+
};
|
|
45702
|
+
}
|
|
45331
45703
|
|
|
45332
45704
|
// packages/zaku/dist/lib/handlers/save-library.js
|
|
45705
|
+
function librarySaveTarget(config2, key) {
|
|
45706
|
+
const graph = designGraph(config2);
|
|
45707
|
+
const keys = [...graph.libraries, ...graph.kits].map((file2) => file2.key);
|
|
45708
|
+
if (keys.length === 0) {
|
|
45709
|
+
const byRole2 = config2.figma.libraries !== void 0 || config2.figma.kits !== void 0;
|
|
45710
|
+
throw new FigmaFileKeyMissing(byRole2 ? "figma.libraries" : "figma.library");
|
|
45711
|
+
}
|
|
45712
|
+
const library = key === void 0 ? graph.libraries.length === 1 ? graph.libraries[0] : void 0 : void 0;
|
|
45713
|
+
if (library)
|
|
45714
|
+
return { kind: "library", library, legacy: graph.legacy };
|
|
45715
|
+
if (key === void 0)
|
|
45716
|
+
throw new LibraryKeyMissing(keys);
|
|
45717
|
+
const named = graph.libraries.find((candidate) => candidate.key === key);
|
|
45718
|
+
if (named)
|
|
45719
|
+
return { kind: "library", library: named, legacy: graph.legacy };
|
|
45720
|
+
const kit = graph.kits.find((candidate) => candidate.key === key);
|
|
45721
|
+
if (kit)
|
|
45722
|
+
return { kind: "kit", kit };
|
|
45723
|
+
throw new LibraryKeyMissing(keys, key);
|
|
45724
|
+
}
|
|
45333
45725
|
async function saveLibrary(options) {
|
|
45334
45726
|
const paths = designPaths(options.root);
|
|
45335
45727
|
const config2 = await readDesignFile(paths.config, zakuConfigSchema);
|
|
45336
|
-
const
|
|
45337
|
-
if (
|
|
45338
|
-
|
|
45339
|
-
|
|
45340
|
-
|
|
45728
|
+
const target = librarySaveTarget(config2, options.key);
|
|
45729
|
+
if (target.kind === "kit") {
|
|
45730
|
+
const at2 = librarySnapshotDir(paths, target.kit.key);
|
|
45731
|
+
const kit = await readKit({ rest: options.rest, key: target.kit.key, family: target.kit.family });
|
|
45732
|
+
await writeKitSnapshot(at2, kit);
|
|
45733
|
+
return { kind: "kit", dir: relative2(paths.root, at2.library), kit };
|
|
45734
|
+
}
|
|
45735
|
+
if (!options.part)
|
|
45736
|
+
throw new TypeError(`saving library ${target.library.key} needs the variables export`);
|
|
45737
|
+
const { key, branches } = target.library;
|
|
45738
|
+
const at = librarySnapshotDir(paths, target.legacy ? null : key);
|
|
45739
|
+
const snapshot = librarySnapshotSchema.parse(await readLibrary({ rest: options.rest, fileKey: key, part: options.part, branches }));
|
|
45740
|
+
return {
|
|
45741
|
+
kind: "library",
|
|
45742
|
+
dir: relative2(paths.root, at.library),
|
|
45743
|
+
snapshot,
|
|
45744
|
+
...await writeLibrarySnapshot(at, snapshot)
|
|
45745
|
+
};
|
|
45341
45746
|
}
|
|
45342
45747
|
var SaveLibraryHandler = class SaveLibraryHandler2 {
|
|
45343
45748
|
rest;
|
|
@@ -45346,7 +45751,12 @@ var SaveLibraryHandler = class SaveLibraryHandler2 {
|
|
|
45346
45751
|
this.rest = rest;
|
|
45347
45752
|
}
|
|
45348
45753
|
handle(command) {
|
|
45349
|
-
return saveLibrary({
|
|
45754
|
+
return saveLibrary({
|
|
45755
|
+
root: command.root,
|
|
45756
|
+
rest: this.rest,
|
|
45757
|
+
...command.key !== void 0 ? { key: command.key } : {},
|
|
45758
|
+
...command.part !== void 0 ? { part: command.part } : {}
|
|
45759
|
+
});
|
|
45350
45760
|
}
|
|
45351
45761
|
};
|
|
45352
45762
|
SaveLibraryHandler = __decorate2([
|
|
@@ -45356,9 +45766,10 @@ SaveLibraryHandler = __decorate2([
|
|
|
45356
45766
|
|
|
45357
45767
|
// packages/zaku/dist/lib/handlers/write-outline.js
|
|
45358
45768
|
var import_tsyringe4 = __toESM(require_cjs(), 1);
|
|
45769
|
+
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
45359
45770
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
45360
45771
|
import { mkdir as mkdir2, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
|
|
45361
|
-
import { dirname as dirname2 } from "node:path";
|
|
45772
|
+
import { dirname as dirname2, join as join6 } from "node:path";
|
|
45362
45773
|
|
|
45363
45774
|
// packages/zaku/dist/lib/domain/documentation-measures.js
|
|
45364
45775
|
var COVER = {
|
|
@@ -45866,6 +46277,9 @@ function indexTitles(maps) {
|
|
|
45866
46277
|
return { titles, duplicates };
|
|
45867
46278
|
}
|
|
45868
46279
|
|
|
46280
|
+
// packages/zaku/dist/lib/adapters/figma-rest-outline.js
|
|
46281
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
46282
|
+
|
|
45869
46283
|
// packages/zaku/dist/lib/domain/layer-names.js
|
|
45870
46284
|
var DEFAULT_NAMES = {
|
|
45871
46285
|
FRAME: ["Frame"],
|
|
@@ -45934,7 +46348,7 @@ function outlineFrame(frame, where, ctx) {
|
|
|
45934
46348
|
const images2 = [];
|
|
45935
46349
|
const defaultNames = [];
|
|
45936
46350
|
const links = [];
|
|
45937
|
-
const
|
|
46351
|
+
const relative3 = (node2) => {
|
|
45938
46352
|
const box = node2.absoluteBoundingBox;
|
|
45939
46353
|
return box ? { x: box.x - origin.x, y: box.y - origin.y, width: box.width, height: box.height } : null;
|
|
45940
46354
|
};
|
|
@@ -45963,7 +46377,7 @@ function outlineFrame(frame, where, ctx) {
|
|
|
45963
46377
|
componentKey: ctx.components[child.componentId ?? ""]?.key ?? "",
|
|
45964
46378
|
component: component2,
|
|
45965
46379
|
interactive: ctx.interactive.has(component2),
|
|
45966
|
-
bounds:
|
|
46380
|
+
bounds: relative3(child)
|
|
45967
46381
|
});
|
|
45968
46382
|
} else if (child.type === "TEXT") {
|
|
45969
46383
|
instance.texts.push({
|
|
@@ -46004,7 +46418,7 @@ function outlineFrame(frame, where, ctx) {
|
|
|
46004
46418
|
texts: [],
|
|
46005
46419
|
interactive: ctx.interactive.has(component2),
|
|
46006
46420
|
local: meta3?.remote === false,
|
|
46007
|
-
bounds:
|
|
46421
|
+
bounds: relative3(node2),
|
|
46008
46422
|
sizing: {
|
|
46009
46423
|
horizontal: node2.layoutSizingHorizontal ?? "FIXED",
|
|
46010
46424
|
vertical: node2.layoutSizingVertical ?? "FIXED"
|
|
@@ -46053,6 +46467,17 @@ function outlineFrame(frame, where, ctx) {
|
|
|
46053
46467
|
links.push(...linksOf(frame));
|
|
46054
46468
|
for (const child of shown(frame))
|
|
46055
46469
|
walk(child);
|
|
46470
|
+
const drawn = {
|
|
46471
|
+
size: [origin.width, origin.height],
|
|
46472
|
+
instances: instances.map((instance) => [
|
|
46473
|
+
instance.componentKey,
|
|
46474
|
+
instance.variant,
|
|
46475
|
+
instance.properties,
|
|
46476
|
+
instance.texts.map((text) => text.characters),
|
|
46477
|
+
instance.bounds
|
|
46478
|
+
]),
|
|
46479
|
+
texts: texts.map((text) => text.characters)
|
|
46480
|
+
};
|
|
46056
46481
|
return {
|
|
46057
46482
|
nodeId: frame.id,
|
|
46058
46483
|
name: frame.name,
|
|
@@ -46066,7 +46491,8 @@ function outlineFrame(frame, where, ctx) {
|
|
|
46066
46491
|
raw,
|
|
46067
46492
|
images: images2,
|
|
46068
46493
|
defaultNames,
|
|
46069
|
-
links
|
|
46494
|
+
links,
|
|
46495
|
+
digest: createHash2("sha256").update(JSON.stringify(drawn)).digest("hex").slice(0, 16)
|
|
46070
46496
|
};
|
|
46071
46497
|
}
|
|
46072
46498
|
|
|
@@ -46132,36 +46558,78 @@ var frameOutlineSchema = external_exports.object({
|
|
|
46132
46558
|
raw: external_exports.array(rawOutlineSchema),
|
|
46133
46559
|
images: external_exports.array(imageOutlineSchema),
|
|
46134
46560
|
defaultNames: external_exports.array(external_exports.object({ nodeId: external_exports.string(), name: external_exports.string() }).strict()),
|
|
46135
|
-
links: external_exports.array(linkOutlineSchema)
|
|
46561
|
+
links: external_exports.array(linkOutlineSchema),
|
|
46562
|
+
/** In a product file of one page per screen: the page the frame is on, and the product file it is in. */
|
|
46563
|
+
page: external_exports.string().optional(),
|
|
46564
|
+
source: external_exports.string().optional(),
|
|
46565
|
+
/** What the frame draws, without its node ids, so a copy and its source digest alike. */
|
|
46566
|
+
digest: external_exports.string().optional()
|
|
46136
46567
|
}).strict();
|
|
46137
|
-
var
|
|
46568
|
+
var flowOutlineSchema = external_exports.object({
|
|
46569
|
+
/** The Figma file key the page is in. */
|
|
46570
|
+
source: external_exports.string(),
|
|
46571
|
+
page: external_exports.string(),
|
|
46572
|
+
fileVersion: external_exports.string(),
|
|
46573
|
+
frames: external_exports.array(external_exports.object({
|
|
46574
|
+
nodeId: external_exports.string(),
|
|
46575
|
+
name: external_exports.string(),
|
|
46576
|
+
screen: external_exports.string().nullable(),
|
|
46577
|
+
target: external_exports.string(),
|
|
46578
|
+
state: external_exports.string(),
|
|
46579
|
+
start: external_exports.boolean(),
|
|
46580
|
+
links: external_exports.array(linkOutlineSchema),
|
|
46581
|
+
digest: external_exports.string()
|
|
46582
|
+
}).strict())
|
|
46583
|
+
}).strict();
|
|
46584
|
+
var LEGACY_LIBRARY_VERSION = "figma.library";
|
|
46585
|
+
function legacyVersion(value) {
|
|
46586
|
+
if (value === null || typeof value !== "object" || !("libraryVersion" in value))
|
|
46587
|
+
return value;
|
|
46588
|
+
const { libraryVersion, ...rest } = value;
|
|
46589
|
+
return {
|
|
46590
|
+
...rest,
|
|
46591
|
+
libraryVersions: typeof libraryVersion === "string" ? { [LEGACY_LIBRARY_VERSION]: libraryVersion } : {}
|
|
46592
|
+
};
|
|
46593
|
+
}
|
|
46594
|
+
var screenOutlineSchema = external_exports.preprocess(legacyVersion, external_exports.object({
|
|
46138
46595
|
feature: external_exports.string(),
|
|
46139
46596
|
screen: external_exports.string(),
|
|
46140
46597
|
/** The Figma file key the frames were read from. */
|
|
46141
46598
|
source: external_exports.string(),
|
|
46142
46599
|
fileVersion: external_exports.string(),
|
|
46143
46600
|
mapDigest: external_exports.string(),
|
|
46144
|
-
|
|
46601
|
+
/** The version of each library snapshot the frames were read against, by key. */
|
|
46602
|
+
libraryVersions: external_exports.record(external_exports.string(), external_exports.string()),
|
|
46603
|
+
/** The version of every product file zaku.yaml lists, when it lists them by family. */
|
|
46604
|
+
fileVersions: external_exports.record(external_exports.string(), external_exports.string()).optional(),
|
|
46145
46605
|
frames: external_exports.array(frameOutlineSchema)
|
|
46146
|
-
}).strict();
|
|
46606
|
+
}).strict());
|
|
46147
46607
|
var unmappedSchema = external_exports.object({
|
|
46148
46608
|
fileVersion: external_exports.string(),
|
|
46149
|
-
frames: external_exports.array(external_exports.object({ nodeId: external_exports.string(), name: external_exports.string() }).strict())
|
|
46609
|
+
frames: external_exports.array(external_exports.object({ nodeId: external_exports.string(), name: external_exports.string() }).strict()),
|
|
46610
|
+
/** A component drawn on a product page, which belongs in a Components library. */
|
|
46611
|
+
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()
|
|
46150
46612
|
}).strict();
|
|
46151
46613
|
|
|
46152
46614
|
// packages/zaku/dist/lib/repositories/outlines.js
|
|
46615
|
+
var FLOWS_DIR = "flows";
|
|
46616
|
+
function flowOutlinePath(dir, source, page) {
|
|
46617
|
+
const slug2 = page.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "page";
|
|
46618
|
+
return join5(dir, FLOWS_DIR, source, `${slug2}.yaml`);
|
|
46619
|
+
}
|
|
46153
46620
|
function outlinePath(dir, feature, screen) {
|
|
46154
46621
|
return join5(dir, feature, `${screen}.yaml`);
|
|
46155
46622
|
}
|
|
46156
46623
|
async function loadOutlines(dir) {
|
|
46157
46624
|
const outlines = [];
|
|
46625
|
+
const flows = [];
|
|
46158
46626
|
const errors = [];
|
|
46159
46627
|
let features;
|
|
46160
46628
|
try {
|
|
46161
|
-
features = (await readdir3(dir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
46629
|
+
features = (await readdir3(dir, { withFileTypes: true })).filter((entry) => entry.isDirectory() && entry.name !== FLOWS_DIR).map((entry) => entry.name).sort();
|
|
46162
46630
|
} catch (error62) {
|
|
46163
46631
|
if (error62.code === "ENOENT")
|
|
46164
|
-
return { outlines, unmapped: null, errors };
|
|
46632
|
+
return { outlines, flows, unmapped: null, errors };
|
|
46165
46633
|
throw error62;
|
|
46166
46634
|
}
|
|
46167
46635
|
for (const feature of features) {
|
|
@@ -46177,6 +46645,24 @@ async function loadOutlines(dir) {
|
|
|
46177
46645
|
}
|
|
46178
46646
|
}
|
|
46179
46647
|
}
|
|
46648
|
+
const sources = await readdir3(join5(dir, FLOWS_DIR)).catch((error62) => {
|
|
46649
|
+
if (error62.code === "ENOENT")
|
|
46650
|
+
return [];
|
|
46651
|
+
throw error62;
|
|
46652
|
+
});
|
|
46653
|
+
for (const source of sources.sort()) {
|
|
46654
|
+
const files2 = (await readdir3(join5(dir, FLOWS_DIR, source))).filter((name) => name.endsWith(".yaml")).sort();
|
|
46655
|
+
for (const file2 of files2) {
|
|
46656
|
+
try {
|
|
46657
|
+
flows.push(await readDesignFile(join5(dir, FLOWS_DIR, source, file2), flowOutlineSchema));
|
|
46658
|
+
} catch (error62) {
|
|
46659
|
+
if (error62 instanceof DesignFileInvalid)
|
|
46660
|
+
errors.push(error62);
|
|
46661
|
+
else
|
|
46662
|
+
throw error62;
|
|
46663
|
+
}
|
|
46664
|
+
}
|
|
46665
|
+
}
|
|
46180
46666
|
let unmapped = null;
|
|
46181
46667
|
try {
|
|
46182
46668
|
unmapped = await readOptionalDesignFile(join5(dir, "unmapped.yaml"), unmappedSchema);
|
|
@@ -46186,7 +46672,7 @@ async function loadOutlines(dir) {
|
|
|
46186
46672
|
else
|
|
46187
46673
|
throw error62;
|
|
46188
46674
|
}
|
|
46189
|
-
return { outlines, unmapped, errors };
|
|
46675
|
+
return { outlines, flows, unmapped, errors };
|
|
46190
46676
|
}
|
|
46191
46677
|
|
|
46192
46678
|
// packages/zaku/dist/lib/handlers/write-outline.js
|
|
@@ -46223,95 +46709,202 @@ function resolveFrame(frame, parsed, maps) {
|
|
|
46223
46709
|
return candidates.find((ref) => ref.feature === pageFeature);
|
|
46224
46710
|
return candidates.length === 1 ? candidates[0] : void 0;
|
|
46225
46711
|
}
|
|
46712
|
+
function resolveTitle(parsed, maps) {
|
|
46713
|
+
const candidates = [...indexScreens(maps).values()].filter((ref) => ref.screen.title === parsed.title);
|
|
46714
|
+
return candidates.length === 1 ? candidates[0] : void 0;
|
|
46715
|
+
}
|
|
46226
46716
|
function looksLikeScreenFrame(name) {
|
|
46227
46717
|
return name.includes("/");
|
|
46228
46718
|
}
|
|
46229
|
-
function holdsScreens(page) {
|
|
46719
|
+
function holdsScreens(page, prototypes = /* @__PURE__ */ new Set()) {
|
|
46230
46720
|
if (page === COVER.page || page === DOCUMENTATION_COMPONENTS_PAGE || page === DIRECTIONS_PAGE)
|
|
46231
46721
|
return false;
|
|
46722
|
+
if (prototypes.has(page))
|
|
46723
|
+
return false;
|
|
46232
46724
|
return !page.startsWith("\u2756 ") && !page.includes(" / ") && !/^-+$/.test(page);
|
|
46233
46725
|
}
|
|
46726
|
+
function listComponents(document, source) {
|
|
46727
|
+
const out = [];
|
|
46728
|
+
for (const page of document.children ?? []) {
|
|
46729
|
+
if (page.type !== "CANVAS" || !holdsScreens(page.name))
|
|
46730
|
+
continue;
|
|
46731
|
+
const walk = (node2) => {
|
|
46732
|
+
for (const child of node2.children ?? []) {
|
|
46733
|
+
if (child.type === "COMPONENT" || child.type === "COMPONENT_SET")
|
|
46734
|
+
out.push({ nodeId: child.id, name: child.name, page: page.name, source });
|
|
46735
|
+
else if (child.type === "SECTION")
|
|
46736
|
+
walk(child);
|
|
46737
|
+
}
|
|
46738
|
+
};
|
|
46739
|
+
walk(page);
|
|
46740
|
+
}
|
|
46741
|
+
return out;
|
|
46742
|
+
}
|
|
46743
|
+
function productFiles(config2) {
|
|
46744
|
+
const graph = designGraph(config2);
|
|
46745
|
+
if (graph.legacy)
|
|
46746
|
+
return config2.figma.product === void 0 ? [] : [{ key: config2.figma.product, targets: config2.targets }];
|
|
46747
|
+
return graph.products.map((product) => ({
|
|
46748
|
+
key: product.key,
|
|
46749
|
+
targets: graph.targetsOf(product.family)
|
|
46750
|
+
}));
|
|
46751
|
+
}
|
|
46234
46752
|
async function runOutline(options) {
|
|
46235
46753
|
const paths = designPaths(options.root);
|
|
46236
46754
|
const config2 = await readDesignFile(paths.config, zakuConfigSchema);
|
|
46237
|
-
const
|
|
46238
|
-
|
|
46239
|
-
|
|
46755
|
+
const { libraries: listed, kits, products: byFamily, prototypes: flows } = config2.figma;
|
|
46756
|
+
const legacy = [listed, kits, byFamily, flows].every((files2) => files2 === void 0);
|
|
46757
|
+
const products = productFiles(config2);
|
|
46758
|
+
if (products.length === 0)
|
|
46759
|
+
throw new FigmaFileKeyMissing(legacy ? "figma.product" : "figma.products");
|
|
46240
46760
|
const { maps, errors } = await loadMaps(paths.maps);
|
|
46241
46761
|
if (errors[0])
|
|
46242
46762
|
throw errors[0];
|
|
46243
46763
|
const digests = new Map(maps.map((loaded) => [loaded.map.feature, loaded.digest]));
|
|
46244
|
-
const
|
|
46764
|
+
const { libraries } = await readDesignSnapshots(paths, config2);
|
|
46765
|
+
const libraryVersions = Object.fromEntries(Object.entries(libraries).map(([key, library]) => [key, library.version]));
|
|
46245
46766
|
const existing = await loadOutlines(paths.outline);
|
|
46246
|
-
const
|
|
46247
|
-
const
|
|
46767
|
+
const prototypes = new Set(legacy ? config2.targets.map((target) => `${target.name} prototype`) : []);
|
|
46768
|
+
const versions = {};
|
|
46769
|
+
const flowPages = /* @__PURE__ */ new Map();
|
|
46770
|
+
const flowFrame = (source, frame, targets) => {
|
|
46771
|
+
const parsed = parseFrameName(frame.name, targets);
|
|
46772
|
+
if (!parsed)
|
|
46773
|
+
return;
|
|
46774
|
+
const key = `${source}
|
|
46775
|
+
${frame.page}`;
|
|
46776
|
+
const page = flowPages.get(key) ?? { source, page: frame.page, frames: [] };
|
|
46777
|
+
page.frames.push({ frame, parsed });
|
|
46778
|
+
flowPages.set(key, page);
|
|
46779
|
+
};
|
|
46248
46780
|
const resolved = /* @__PURE__ */ new Map();
|
|
46249
|
-
const unmapped = { fileVersion:
|
|
46250
|
-
|
|
46251
|
-
|
|
46252
|
-
|
|
46253
|
-
|
|
46781
|
+
const unmapped = { fileVersion: "", frames: [] };
|
|
46782
|
+
const components = [];
|
|
46783
|
+
for (const product of products) {
|
|
46784
|
+
const file2 = await options.rest.file(product.key, INDEX_DEPTH);
|
|
46785
|
+
versions[product.key] = file2.version;
|
|
46786
|
+
const listed2 = listFrames(file2.document);
|
|
46787
|
+
for (const frame of listed2.filter((candidate) => prototypes.has(candidate.page)))
|
|
46788
|
+
flowFrame(product.key, frame, product.targets);
|
|
46789
|
+
for (const frame of listed2.filter((candidate) => holdsScreens(candidate.page, prototypes))) {
|
|
46790
|
+
const parsed = parseFrameName(frame.name, product.targets);
|
|
46791
|
+
if (!parsed) {
|
|
46792
|
+
if (looksLikeScreenFrame(frame.name))
|
|
46793
|
+
unmapped.frames.push({ nodeId: frame.id, name: frame.name });
|
|
46794
|
+
continue;
|
|
46795
|
+
}
|
|
46796
|
+
const ref = legacy ? resolveFrame(frame, parsed, maps) : resolveTitle(parsed, maps);
|
|
46797
|
+
if (ref)
|
|
46798
|
+
resolved.set(frame.id, { frame, parsed, ref, source: product.key });
|
|
46799
|
+
else
|
|
46254
46800
|
unmapped.frames.push({ nodeId: frame.id, name: frame.name });
|
|
46255
|
-
continue;
|
|
46256
46801
|
}
|
|
46257
|
-
|
|
46258
|
-
|
|
46259
|
-
|
|
46260
|
-
|
|
46261
|
-
|
|
46802
|
+
if (!legacy)
|
|
46803
|
+
components.push(...listComponents(file2.document, product.key));
|
|
46804
|
+
}
|
|
46805
|
+
const graph = designGraph(config2);
|
|
46806
|
+
for (const file2 of legacy ? [] : graph.prototypes) {
|
|
46807
|
+
const read = await options.rest.file(file2.key, INDEX_DEPTH);
|
|
46808
|
+
versions[file2.key] = read.version;
|
|
46809
|
+
const targets = graph.targetsOf(file2.family);
|
|
46810
|
+
for (const frame of listFrames(read.document).filter((candidate) => holdsScreens(candidate.page)))
|
|
46811
|
+
flowFrame(file2.key, frame, targets);
|
|
46262
46812
|
}
|
|
46813
|
+
unmapped.fileVersion = Object.values(versions).join(",");
|
|
46814
|
+
if (!legacy)
|
|
46815
|
+
unmapped.components = components;
|
|
46263
46816
|
const outlined = new Set(existing.outlines.flatMap((outline) => outline.frames.map((frame) => frame.nodeId)));
|
|
46264
46817
|
const drawnScreens = new Set([...resolved.values()].map(({ ref }) => `${ref.feature}/${ref.id}`));
|
|
46265
|
-
const current = existing.outlines.every((outline) => outline.fileVersion ===
|
|
46818
|
+
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}`));
|
|
46266
46819
|
if (options.frames === null && existing.outlines.length > 0 && current) {
|
|
46267
46820
|
return { skipped: true, read: 0, written: [], unmapped: unmapped.frames.length };
|
|
46268
46821
|
}
|
|
46269
46822
|
const ids = options.frames ?? [...resolved.keys()];
|
|
46270
|
-
const response = ids.length > 0 ? await options.rest.nodes(fileKey2, ids) : { version: file2.version, nodes: {} };
|
|
46271
46823
|
const byScreen = /* @__PURE__ */ new Map();
|
|
46272
46824
|
if (options.frames !== null) {
|
|
46273
46825
|
for (const outline of existing.outlines)
|
|
46274
46826
|
byScreen.set(`${outline.feature}/${outline.screen}`, outline);
|
|
46275
46827
|
}
|
|
46276
46828
|
const interactive = new Set(config2.interactive);
|
|
46277
|
-
|
|
46278
|
-
|
|
46279
|
-
|
|
46280
|
-
const read = await options.rest.nodes(fileKey2, [...resized]);
|
|
46281
|
-
for (const [id2, entry] of Object.entries(read.nodes)) {
|
|
46282
|
-
const box = entry?.document.absoluteBoundingBox;
|
|
46283
|
-
if (box)
|
|
46284
|
-
sizes.set(id2, { width: box.width, height: box.height });
|
|
46285
|
-
}
|
|
46286
|
-
}
|
|
46287
|
-
for (const [id2, entry] of Object.entries(response.nodes)) {
|
|
46288
|
-
const found = resolved.get(id2);
|
|
46289
|
-
if (!entry || !found)
|
|
46829
|
+
for (const product of products) {
|
|
46830
|
+
const own2 = ids.filter((id2) => resolved.has(id2) ? resolved.get(id2)?.source === product.key : product === products[0]);
|
|
46831
|
+
if (own2.length === 0)
|
|
46290
46832
|
continue;
|
|
46291
|
-
const
|
|
46292
|
-
const
|
|
46293
|
-
const
|
|
46294
|
-
|
|
46295
|
-
|
|
46296
|
-
|
|
46297
|
-
|
|
46298
|
-
|
|
46299
|
-
|
|
46300
|
-
|
|
46301
|
-
}
|
|
46302
|
-
const
|
|
46303
|
-
|
|
46304
|
-
|
|
46305
|
-
|
|
46306
|
-
|
|
46307
|
-
|
|
46308
|
-
|
|
46309
|
-
|
|
46310
|
-
|
|
46311
|
-
|
|
46312
|
-
|
|
46833
|
+
const response = await options.rest.nodes(product.key, own2);
|
|
46834
|
+
const resized = new Set(Object.values(response.nodes).flatMap((entry) => entry ? resizedLocalComponents(entry.document, entry.components) : []));
|
|
46835
|
+
const sizes = /* @__PURE__ */ new Map();
|
|
46836
|
+
if (resized.size > 0) {
|
|
46837
|
+
const read = await options.rest.nodes(product.key, [...resized]);
|
|
46838
|
+
for (const [id2, entry] of Object.entries(read.nodes)) {
|
|
46839
|
+
const box = entry?.document.absoluteBoundingBox;
|
|
46840
|
+
if (box)
|
|
46841
|
+
sizes.set(id2, { width: box.width, height: box.height });
|
|
46842
|
+
}
|
|
46843
|
+
}
|
|
46844
|
+
for (const [id2, entry] of Object.entries(response.nodes)) {
|
|
46845
|
+
const found = resolved.get(id2);
|
|
46846
|
+
if (!entry || !found)
|
|
46847
|
+
continue;
|
|
46848
|
+
const { frame: place, parsed, ref } = found;
|
|
46849
|
+
const key = `${ref.feature}/${ref.id}`;
|
|
46850
|
+
const outline = byScreen.get(key) ?? {
|
|
46851
|
+
feature: ref.feature,
|
|
46852
|
+
screen: ref.id,
|
|
46853
|
+
source: product.key,
|
|
46854
|
+
fileVersion: versions[product.key] ?? "",
|
|
46855
|
+
mapDigest: "",
|
|
46856
|
+
libraryVersions: {},
|
|
46857
|
+
frames: []
|
|
46858
|
+
};
|
|
46859
|
+
const frame = outlineFrame(entry.document, {
|
|
46860
|
+
target: parsed.target.id,
|
|
46861
|
+
state: parsed.state,
|
|
46862
|
+
containers: place.containers,
|
|
46863
|
+
start: place.start
|
|
46864
|
+
}, { ...entry, interactive, sizes });
|
|
46865
|
+
if (!legacy)
|
|
46866
|
+
Object.assign(frame, { page: place.page, source: product.key });
|
|
46867
|
+
outline.frames = [...outline.frames.filter((kept) => kept.nodeId !== id2), frame].sort((a, b) => a.name.localeCompare(b.name));
|
|
46868
|
+
outline.mapDigest = digests.get(ref.feature) ?? "";
|
|
46869
|
+
outline.libraryVersions = libraryVersions;
|
|
46870
|
+
if (legacy)
|
|
46871
|
+
outline.fileVersion = versions[product.key] ?? "";
|
|
46872
|
+
else
|
|
46873
|
+
outline.fileVersions = versions;
|
|
46874
|
+
byScreen.set(key, outline);
|
|
46875
|
+
}
|
|
46313
46876
|
}
|
|
46314
46877
|
if (options.frames === null) {
|
|
46878
|
+
await rm2(join6(paths.outline, FLOWS_DIR), { recursive: true, force: true });
|
|
46879
|
+
for (const page of flowPages.values()) {
|
|
46880
|
+
const response = await options.rest.nodes(page.source, page.frames.map(({ frame }) => frame.id));
|
|
46881
|
+
const flow = {
|
|
46882
|
+
source: page.source,
|
|
46883
|
+
page: page.page,
|
|
46884
|
+
fileVersion: versions[page.source] ?? "",
|
|
46885
|
+
frames: []
|
|
46886
|
+
};
|
|
46887
|
+
for (const { frame, parsed } of page.frames) {
|
|
46888
|
+
const entry = response.nodes[frame.id];
|
|
46889
|
+
if (!entry)
|
|
46890
|
+
continue;
|
|
46891
|
+
const read = outlineFrame(entry.document, { target: parsed.target.id, state: parsed.state, containers: frame.containers, start: frame.start }, { ...entry, interactive, sizes: /* @__PURE__ */ new Map() });
|
|
46892
|
+
const ref = resolveTitle(parsed, maps);
|
|
46893
|
+
flow.frames.push({
|
|
46894
|
+
nodeId: frame.id,
|
|
46895
|
+
name: frame.name,
|
|
46896
|
+
screen: ref ? `${ref.feature}/${ref.id}` : null,
|
|
46897
|
+
target: parsed.target.id,
|
|
46898
|
+
state: parsed.state,
|
|
46899
|
+
start: frame.start,
|
|
46900
|
+
links: read.links,
|
|
46901
|
+
digest: read.digest ?? ""
|
|
46902
|
+
});
|
|
46903
|
+
}
|
|
46904
|
+
const path2 = flowOutlinePath(paths.outline, page.source, page.page);
|
|
46905
|
+
await mkdir2(dirname2(path2), { recursive: true });
|
|
46906
|
+
await writeFile3(path2, (0, import_yaml2.stringify)(flow));
|
|
46907
|
+
}
|
|
46315
46908
|
for (const outline of existing.outlines) {
|
|
46316
46909
|
if (!byScreen.has(`${outline.feature}/${outline.screen}`))
|
|
46317
46910
|
await rm2(outlinePath(paths.outline, outline.feature, outline.screen), { force: true });
|
|
@@ -46441,13 +47034,13 @@ RecipeRepository = __decorate2([
|
|
|
46441
47034
|
// packages/zaku/dist/lib/repositories/json-schema-files.js
|
|
46442
47035
|
var import_tsyringe10 = __toESM(require_cjs(), 1);
|
|
46443
47036
|
import { mkdir as mkdir3 } from "node:fs/promises";
|
|
46444
|
-
import { join as
|
|
47037
|
+
import { join as join7 } from "node:path";
|
|
46445
47038
|
var JsonSchemaFiles = class JsonSchemaFiles2 {
|
|
46446
47039
|
async write(dir, schemas) {
|
|
46447
47040
|
await mkdir3(dir, { recursive: true });
|
|
46448
47041
|
const written = [];
|
|
46449
47042
|
for (const [name, schema] of Object.entries(schemas)) {
|
|
46450
|
-
const path2 =
|
|
47043
|
+
const path2 = join7(dir, name);
|
|
46451
47044
|
await writeDesignFile(path2, schema);
|
|
46452
47045
|
written.push(path2);
|
|
46453
47046
|
}
|
|
@@ -46475,10 +47068,10 @@ SourceFiles = __decorate2([
|
|
|
46475
47068
|
|
|
46476
47069
|
// packages/zaku/dist/lib/repositories/budget-ledger.js
|
|
46477
47070
|
import { mkdir as mkdir4, readFile as readFile5, rename as rename3, writeFile as writeFile4 } from "node:fs/promises";
|
|
46478
|
-
import { dirname as dirname3, join as
|
|
47071
|
+
import { dirname as dirname3, join as join8 } from "node:path";
|
|
46479
47072
|
function ledgerPath(env, platform, home) {
|
|
46480
|
-
const cache = env["XDG_CACHE_HOME"] ?? (platform === "darwin" ?
|
|
46481
|
-
return
|
|
47073
|
+
const cache = env["XDG_CACHE_HOME"] ?? (platform === "darwin" ? join8(home, "Library", "Caches") : join8(home, ".cache"));
|
|
47074
|
+
return join8(cache, "zaku", "ledger.json");
|
|
46482
47075
|
}
|
|
46483
47076
|
function today(now) {
|
|
46484
47077
|
return now.toISOString().slice(0, 10);
|
|
@@ -46547,6 +47140,31 @@ var pairingSchema = external_exports.object({
|
|
|
46547
47140
|
}).strict();
|
|
46548
47141
|
var pairingsFileSchema = external_exports.object({ pairings: external_exports.array(pairingSchema.extend({ hash: external_exports.string() }).strict()) }).strict();
|
|
46549
47142
|
|
|
47143
|
+
// packages/zaku/dist/lib/domain/print-graph.js
|
|
47144
|
+
function printGraph(config2, snapshots) {
|
|
47145
|
+
const graph = designGraph(config2);
|
|
47146
|
+
const lines = ["targets"];
|
|
47147
|
+
for (const target of config2.targets) {
|
|
47148
|
+
const files2 = [
|
|
47149
|
+
...graph.librariesFor(target).map((library) => `${library.key} ${library.layer}`),
|
|
47150
|
+
...graph.kitsFor(target).map((kit) => `${kit.key} ${kit.family} kit`)
|
|
47151
|
+
];
|
|
47152
|
+
const branch = graph.branchOf(target);
|
|
47153
|
+
const product = graph.products.find((file2) => file2.family === target.family)?.key;
|
|
47154
|
+
lines.push(` ${target.name} (${target.id}, ${branch ? `branch ${branch}` : "no branch"}, ${product ? `product ${product}` : "no product"}): ${files2.join(", ") || "nothing"}`);
|
|
47155
|
+
}
|
|
47156
|
+
lines.push("files");
|
|
47157
|
+
const extendedBy = (key) => graph.libraries.filter((library) => library.extends.includes(key)).map((library) => library.key).join(", ") || "nothing";
|
|
47158
|
+
const saved = (key, present) => present ? "" : ` (no snapshot; run zaku library save --key ${key})`;
|
|
47159
|
+
for (const library of graph.libraries) {
|
|
47160
|
+
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)}`);
|
|
47161
|
+
}
|
|
47162
|
+
for (const kit of graph.kits) {
|
|
47163
|
+
lines.push(` ${kit.key} ${kit.family} kit: extended by ${extendedBy(kit.key)}${saved(kit.key, snapshots.kits[kit.key] !== void 0)}`);
|
|
47164
|
+
}
|
|
47165
|
+
return lines;
|
|
47166
|
+
}
|
|
47167
|
+
|
|
46550
47168
|
// packages/zaku/dist/lib/adapters/figma-rest.js
|
|
46551
47169
|
var FigmaRateLimited = class extends Error {
|
|
46552
47170
|
url;
|
|
@@ -46591,26 +47209,30 @@ function createFigmaRest(options) {
|
|
|
46591
47209
|
throw new FigmaRateLimited(url2);
|
|
46592
47210
|
}
|
|
46593
47211
|
const chunks = (ids) => Array.from({ length: Math.ceil(ids.length / BATCH) }, (_, index) => ids.slice(index * BATCH, (index + 1) * BATCH));
|
|
47212
|
+
async function components(fileKey3) {
|
|
47213
|
+
const listed = await call(`${BASE}/files/${fileKey3}/components`);
|
|
47214
|
+
return listed.meta.components;
|
|
47215
|
+
}
|
|
46594
47216
|
return {
|
|
46595
|
-
file: (
|
|
46596
|
-
async nodes(
|
|
47217
|
+
file: (fileKey3, depth) => call(`${BASE}/files/${fileKey3}?depth=${depth}`),
|
|
47218
|
+
async nodes(fileKey3, ids) {
|
|
46597
47219
|
const merged = { version: "", nodes: {} };
|
|
46598
47220
|
for (const chunk of chunks(ids)) {
|
|
46599
|
-
const part = await call(`${BASE}/files/${
|
|
47221
|
+
const part = await call(`${BASE}/files/${fileKey3}/nodes?ids=${encodeURIComponent(chunk.join(","))}`);
|
|
46600
47222
|
merged.version = part.version;
|
|
46601
47223
|
Object.assign(merged.nodes, part.nodes);
|
|
46602
47224
|
}
|
|
46603
47225
|
return merged;
|
|
46604
47226
|
},
|
|
46605
|
-
async published(
|
|
46606
|
-
const sets = await call(`${BASE}/files/${
|
|
46607
|
-
|
|
46608
|
-
return { sets: sets.meta.component_sets, components: components.meta.components };
|
|
47227
|
+
async published(fileKey3) {
|
|
47228
|
+
const sets = await call(`${BASE}/files/${fileKey3}/component_sets`);
|
|
47229
|
+
return { sets: sets.meta.component_sets, components: await components(fileKey3) };
|
|
46609
47230
|
},
|
|
46610
|
-
|
|
47231
|
+
components,
|
|
47232
|
+
async images(fileKey3, ids) {
|
|
46611
47233
|
const merged = {};
|
|
46612
47234
|
for (const chunk of chunks(ids)) {
|
|
46613
|
-
const part = await call(`${BASE}/images/${
|
|
47235
|
+
const part = await call(`${BASE}/images/${fileKey3}?ids=${encodeURIComponent(chunk.join(","))}&format=png&scale=1`);
|
|
46614
47236
|
Object.assign(merged, part.images);
|
|
46615
47237
|
}
|
|
46616
47238
|
return merged;
|
|
@@ -46620,17 +47242,40 @@ function createFigmaRest(options) {
|
|
|
46620
47242
|
|
|
46621
47243
|
// packages/zaku/dist/lib/adapters/figma-variables-script.js
|
|
46622
47244
|
async function exportVariables(figma, options) {
|
|
46623
|
-
const collections = await figma.variables.getLocalVariableCollectionsAsync();
|
|
47245
|
+
const collections = [...await figma.variables.getLocalVariableCollectionsAsync()];
|
|
47246
|
+
if (!collections.some((collection) => collection.name === "semantic")) {
|
|
47247
|
+
const available = await figma.teamLibrary.getAvailableLibraryVariableCollectionsAsync();
|
|
47248
|
+
const bases = [
|
|
47249
|
+
...new Set(available.filter((entry) => entry.name === "semantic").map((entry) => entry.libraryName))
|
|
47250
|
+
];
|
|
47251
|
+
if (bases.length === 0)
|
|
47252
|
+
throw new Error("the file has no semantic collection and no enabled library has one");
|
|
47253
|
+
if (bases.length > 1)
|
|
47254
|
+
throw new Error(`several enabled libraries hold a semantic collection: ${bases.join(", ")}; enable only the one this library extends`);
|
|
47255
|
+
const imported = /* @__PURE__ */ new Map();
|
|
47256
|
+
for (const entry of available.filter((candidate) => candidate.libraryName === bases[0])) {
|
|
47257
|
+
for (const listed of await figma.teamLibrary.getVariablesInLibraryCollectionAsync(entry.key)) {
|
|
47258
|
+
const variable = await figma.variables.importVariableByKeyAsync(listed.key);
|
|
47259
|
+
if (!imported.has(variable.variableCollectionId))
|
|
47260
|
+
imported.set(variable.variableCollectionId, await figma.variables.getVariableCollectionByIdAsync(variable.variableCollectionId));
|
|
47261
|
+
}
|
|
47262
|
+
}
|
|
47263
|
+
collections.push(...[...imported.values()].filter(Boolean));
|
|
47264
|
+
}
|
|
46624
47265
|
const semantic = collections.find((collection) => collection.name === "semantic");
|
|
46625
47266
|
if (!semantic)
|
|
46626
47267
|
throw new Error("the library has no semantic variable collection");
|
|
46627
47268
|
const hex3 = (value) => Math.round(Math.min(1, Math.max(0, value)) * 255).toString(16).padStart(2, "0");
|
|
46628
47269
|
const variables = {};
|
|
47270
|
+
const variableKeys = {};
|
|
46629
47271
|
for (const collection of collections) {
|
|
46630
47272
|
for (const id2 of collection.variableIds) {
|
|
46631
47273
|
const variable = await figma.variables.getVariableByIdAsync(id2);
|
|
46632
|
-
if (variable)
|
|
46633
|
-
|
|
47274
|
+
if (!variable)
|
|
47275
|
+
continue;
|
|
47276
|
+
const short = String(id2).replace(/^VariableID:/, "");
|
|
47277
|
+
variables[short] = variable.name;
|
|
47278
|
+
variableKeys[short] = { key: variable.key, local: variable.remote !== true };
|
|
46634
47279
|
}
|
|
46635
47280
|
}
|
|
46636
47281
|
const holder = figma.createFrame();
|
|
@@ -46652,6 +47297,8 @@ async function exportVariables(figma, options) {
|
|
|
46652
47297
|
const values = {};
|
|
46653
47298
|
for (const id2 of semantic.variableIds) {
|
|
46654
47299
|
const variable = await figma.variables.getVariableByIdAsync(id2);
|
|
47300
|
+
if (!variable)
|
|
47301
|
+
continue;
|
|
46655
47302
|
const resolved = variable.resolveForConsumer(holder).value;
|
|
46656
47303
|
values[variable.name] = typeof resolved === "object" && resolved !== null ? `#${hex3(resolved.r)}${hex3(resolved.g)}${hex3(resolved.b)}${hex3(resolved.a ?? 1)}` : resolved;
|
|
46657
47304
|
}
|
|
@@ -46671,21 +47318,31 @@ async function exportVariables(figma, options) {
|
|
|
46671
47318
|
for (const node2 of page.findAllWithCriteria({ types: ["COMPONENT_SET", "COMPONENT"] })) {
|
|
46672
47319
|
if (node2.type === "COMPONENT" && node2.parent?.type === "COMPONENT_SET")
|
|
46673
47320
|
continue;
|
|
47321
|
+
let view = node2;
|
|
47322
|
+
while (view.parent && view.parent.type !== "PAGE")
|
|
47323
|
+
view = view.parent;
|
|
46674
47324
|
components.push({
|
|
46675
47325
|
id: node2.id,
|
|
46676
47326
|
key: node2.key,
|
|
46677
47327
|
name: node2.name,
|
|
46678
47328
|
page: page.name,
|
|
47329
|
+
...view !== node2 && view.parent ? { frame: view.name } : {},
|
|
46679
47330
|
description: node2.description ?? "",
|
|
46680
47331
|
set: node2.type === "COMPONENT_SET"
|
|
46681
47332
|
});
|
|
46682
47333
|
}
|
|
46683
47334
|
}
|
|
46684
47335
|
}
|
|
47336
|
+
const effectStyles = (await figma.getLocalEffectStylesAsync()).map((style) => ({
|
|
47337
|
+
key: style.key,
|
|
47338
|
+
name: style.name
|
|
47339
|
+
}));
|
|
46685
47340
|
return {
|
|
46686
47341
|
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
46687
47342
|
variables,
|
|
47343
|
+
variableKeys,
|
|
46688
47344
|
textStyles,
|
|
47345
|
+
effectStyles,
|
|
46689
47346
|
tokens,
|
|
46690
47347
|
...options.local ? { components } : {}
|
|
46691
47348
|
};
|
|
@@ -47277,15 +47934,15 @@ async function startPluginBridge(options = {}) {
|
|
|
47277
47934
|
});
|
|
47278
47935
|
});
|
|
47279
47936
|
});
|
|
47280
|
-
function request(
|
|
47937
|
+
function request(fileKey3, message, timeoutMs) {
|
|
47281
47938
|
if (port === null)
|
|
47282
47939
|
return Promise.resolve({
|
|
47283
47940
|
ok: false,
|
|
47284
47941
|
error: `no port from ${ports[0]} to ${ports[ports.length - 1]} was free, so zaku mcp could not listen for the plugin`
|
|
47285
47942
|
});
|
|
47286
|
-
const socket = holderOf(
|
|
47943
|
+
const socket = holderOf(fileKey3);
|
|
47287
47944
|
if (!socket)
|
|
47288
|
-
return Promise.resolve({ ok: false, error: `file ${
|
|
47945
|
+
return Promise.resolve({ ok: false, error: `file ${fileKey3} is not open in Figma with the zaku plugin` });
|
|
47289
47946
|
const id2 = `c${++next}`;
|
|
47290
47947
|
return new Promise((resolve3) => {
|
|
47291
47948
|
const timer = setTimeout(() => settle2(id2, { ok: false, error: `no answer from the zaku panel in ${timeoutMs / 1e3} s; ${PARTIAL}` }), timeoutMs);
|
|
@@ -47295,8 +47952,8 @@ async function startPluginBridge(options = {}) {
|
|
|
47295
47952
|
}
|
|
47296
47953
|
return {
|
|
47297
47954
|
port,
|
|
47298
|
-
run: (
|
|
47299
|
-
screenshot: (
|
|
47955
|
+
run: (fileKey3, call, timeoutMs) => request(fileKey3, { type: "run", ...call }, timeoutMs),
|
|
47956
|
+
screenshot: (fileKey3, call, timeoutMs) => request(fileKey3, { type: "screenshot", ...call }, timeoutMs),
|
|
47300
47957
|
close: () => new Promise((done) => {
|
|
47301
47958
|
if (!server || !bound)
|
|
47302
47959
|
return done();
|
|
@@ -47307,12 +47964,66 @@ async function startPluginBridge(options = {}) {
|
|
|
47307
47964
|
};
|
|
47308
47965
|
}
|
|
47309
47966
|
|
|
47967
|
+
// packages/zaku/dist/lib/domain/checks/libraries.js
|
|
47968
|
+
var comboKey2 = (combo) => JSON.stringify(Object.entries(combo).sort(([a], [b]) => a.localeCompare(b)));
|
|
47969
|
+
function joinLibraries(snapshots) {
|
|
47970
|
+
if (snapshots.length === 1 && snapshots[0])
|
|
47971
|
+
return snapshots[0];
|
|
47972
|
+
const tokens = /* @__PURE__ */ new Map();
|
|
47973
|
+
for (const snapshot of snapshots) {
|
|
47974
|
+
for (const token of snapshot.tokens) {
|
|
47975
|
+
const key = comboKey2(token.combo);
|
|
47976
|
+
tokens.set(key, { combo: token.combo, values: { ...tokens.get(key)?.values, ...token.values } });
|
|
47977
|
+
}
|
|
47978
|
+
}
|
|
47979
|
+
return {
|
|
47980
|
+
source: snapshots.map((snapshot) => snapshot.source).join(","),
|
|
47981
|
+
version: snapshots.map((snapshot) => snapshot.version).join(","),
|
|
47982
|
+
exportedAt: snapshots.map((snapshot) => snapshot.exportedAt).sort().at(-1) ?? "",
|
|
47983
|
+
components: snapshots.flatMap((snapshot) => snapshot.components),
|
|
47984
|
+
textStyles: snapshots.flatMap((snapshot) => snapshot.textStyles),
|
|
47985
|
+
tokens: [...tokens.values()]
|
|
47986
|
+
};
|
|
47987
|
+
}
|
|
47988
|
+
function missingSnapshots(graph, keys) {
|
|
47989
|
+
const paths = keys.map((key) => graph.legacy ? "library/index.json" : `library/${key}/index.json`);
|
|
47990
|
+
return `${paths.join(", ")} ${paths.length === 1 ? "is" : "are"} missing`;
|
|
47991
|
+
}
|
|
47992
|
+
function checkLibraries(input2) {
|
|
47993
|
+
const graph = designGraph(input2.config);
|
|
47994
|
+
const { libraries, missing } = snapshotsFor(input2);
|
|
47995
|
+
const kits = new Set(graph.kits.map((kit) => kit.key));
|
|
47996
|
+
const absent = missing.filter((key) => !kits.has(key));
|
|
47997
|
+
if (absent.length > 0)
|
|
47998
|
+
return { notRun: missingSnapshots(graph, absent) };
|
|
47999
|
+
if (libraries.length === 0)
|
|
48000
|
+
return { notRun: "library/index.json is missing" };
|
|
48001
|
+
const all = joinLibraries(libraries);
|
|
48002
|
+
const joined = /* @__PURE__ */ new Map();
|
|
48003
|
+
return {
|
|
48004
|
+
all,
|
|
48005
|
+
forTarget(targetId) {
|
|
48006
|
+
const target = input2.config.targets.find((candidate) => candidate.id === targetId);
|
|
48007
|
+
if (!target)
|
|
48008
|
+
return all;
|
|
48009
|
+
const cached2 = joined.get(targetId);
|
|
48010
|
+
if (cached2)
|
|
48011
|
+
return cached2;
|
|
48012
|
+
const own2 = joinLibraries(snapshotsFor(input2, target).libraries);
|
|
48013
|
+
joined.set(targetId, own2);
|
|
48014
|
+
return own2;
|
|
48015
|
+
}
|
|
48016
|
+
};
|
|
48017
|
+
}
|
|
48018
|
+
|
|
47310
48019
|
// packages/zaku/dist/lib/domain/checks/binding.js
|
|
47311
48020
|
var PAINTS = ["fill", "stroke", "textColor", "glyph"];
|
|
47312
48021
|
var SEMANTIC = /^(color|mode|radius)\//;
|
|
47313
|
-
var binding = (
|
|
47314
|
-
|
|
47315
|
-
|
|
48022
|
+
var binding = (input2) => {
|
|
48023
|
+
const libraries = checkLibraries(input2);
|
|
48024
|
+
if ("notRun" in libraries)
|
|
48025
|
+
return libraries;
|
|
48026
|
+
const library = libraries.all;
|
|
47316
48027
|
const findings = [];
|
|
47317
48028
|
for (const component2 of library.components) {
|
|
47318
48029
|
for (const variant of component2.variants) {
|
|
@@ -47678,8 +48389,9 @@ var frameCheck = ({ config: config2, outlines }) => {
|
|
|
47678
48389
|
}
|
|
47679
48390
|
return { findings };
|
|
47680
48391
|
};
|
|
47681
|
-
var systemBars = ({ config: config2, outlines }) => {
|
|
48392
|
+
var systemBars = ({ config: config2, outlines, kits }) => {
|
|
47682
48393
|
const families2 = new Map(config2.targets.map((target) => [target.id, target.family]));
|
|
48394
|
+
const graph = designGraph(config2);
|
|
47683
48395
|
const bars = { ...DEFAULT_SYSTEM_BARS, ...config2.systemBars };
|
|
47684
48396
|
const findings = [];
|
|
47685
48397
|
for (const outline of outlines) {
|
|
@@ -47687,7 +48399,10 @@ var systemBars = ({ config: config2, outlines }) => {
|
|
|
47687
48399
|
const family = families2.get(frame.target);
|
|
47688
48400
|
if (!family)
|
|
47689
48401
|
continue;
|
|
47690
|
-
const
|
|
48402
|
+
const own2 = graph.kits.filter((kit) => kit.family === family && kits[kit.key]);
|
|
48403
|
+
const kitKeys = new Set(own2.flatMap((kit) => kits[kit.key]?.components.map((component2) => component2.key) ?? []));
|
|
48404
|
+
const from = own2.length > 0 ? ` from ${own2.map((kit) => kit.key).join(" or ")}` : "";
|
|
48405
|
+
const held = new Set(frame.instances.filter((instance) => own2.length === 0 || kitKeys.has(instance.componentKey)).map((instance) => instance.component));
|
|
47691
48406
|
for (const names of bars[family]) {
|
|
47692
48407
|
if (!names.some((name) => held.has(name))) {
|
|
47693
48408
|
findings.push({
|
|
@@ -47696,7 +48411,7 @@ var systemBars = ({ config: config2, outlines }) => {
|
|
|
47696
48411
|
screen: outline.screen,
|
|
47697
48412
|
frame: frame.name,
|
|
47698
48413
|
nodeId: frame.nodeId,
|
|
47699
|
-
message: `no ${names.join(" or ")} instance on a ${family} frame`
|
|
48414
|
+
message: `no ${names.join(" or ")} instance${from} on a ${family} frame`
|
|
47700
48415
|
});
|
|
47701
48416
|
}
|
|
47702
48417
|
}
|
|
@@ -47710,6 +48425,18 @@ var placement = ({ maps, outlines }) => {
|
|
|
47710
48425
|
for (const outline of outlines) {
|
|
47711
48426
|
const title = titles.get(`${outline.feature}/${outline.screen}`);
|
|
47712
48427
|
for (const frame of outline.frames) {
|
|
48428
|
+
if (frame.page !== void 0) {
|
|
48429
|
+
if (title !== void 0 && frame.page !== title)
|
|
48430
|
+
findings.push({
|
|
48431
|
+
check: "placement",
|
|
48432
|
+
feature: outline.feature,
|
|
48433
|
+
screen: outline.screen,
|
|
48434
|
+
frame: frame.name,
|
|
48435
|
+
nodeId: frame.nodeId,
|
|
48436
|
+
message: `sits on the page ${frame.page}, and its screen is drawn on the page ${title}`
|
|
48437
|
+
});
|
|
48438
|
+
continue;
|
|
48439
|
+
}
|
|
47713
48440
|
const expected = [title, frame.state];
|
|
47714
48441
|
if (frame.containers.length !== 2 || frame.containers[0] !== expected[0] || frame.containers[1] !== expected[1]) {
|
|
47715
48442
|
findings.push({
|
|
@@ -47743,8 +48470,19 @@ var naming = ({ outlines }) => {
|
|
|
47743
48470
|
}
|
|
47744
48471
|
return { findings };
|
|
47745
48472
|
};
|
|
47746
|
-
var component = ({ outlines }) => {
|
|
48473
|
+
var component = ({ config: config2, outlines, productComponents }) => {
|
|
47747
48474
|
const findings = [];
|
|
48475
|
+
const graph = designGraph(config2);
|
|
48476
|
+
for (const drawn of productComponents) {
|
|
48477
|
+
const families2 = graph.products.filter((product) => product.key === drawn.source).map((product) => product.family);
|
|
48478
|
+
const branches = new Set(families2.flatMap((family) => graph.targetsOf(family)).flatMap((target) => graph.branchOf(target) ?? []));
|
|
48479
|
+
const homes = graph.libraries.filter((library) => library.layer === "components" && library.branches.some((branch) => branches.has(branch))).map((library) => library.key);
|
|
48480
|
+
findings.push({
|
|
48481
|
+
check: "component",
|
|
48482
|
+
nodeId: drawn.nodeId,
|
|
48483
|
+
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`}`
|
|
48484
|
+
});
|
|
48485
|
+
}
|
|
47748
48486
|
for (const outline of outlines) {
|
|
47749
48487
|
const seen = /* @__PURE__ */ new Map();
|
|
47750
48488
|
for (const frame of outline.frames) {
|
|
@@ -47776,13 +48514,16 @@ var component = ({ outlines }) => {
|
|
|
47776
48514
|
};
|
|
47777
48515
|
|
|
47778
48516
|
// packages/zaku/dist/lib/domain/checks/font.js
|
|
47779
|
-
var font = (
|
|
47780
|
-
|
|
47781
|
-
|
|
47782
|
-
|
|
48517
|
+
var font = (input2) => {
|
|
48518
|
+
const libraries = checkLibraries(input2);
|
|
48519
|
+
if ("notRun" in libraries)
|
|
48520
|
+
return libraries;
|
|
48521
|
+
const keys = /* @__PURE__ */ new Map();
|
|
47783
48522
|
const findings = [];
|
|
47784
|
-
for (const outline of outlines) {
|
|
48523
|
+
for (const outline of input2.outlines) {
|
|
47785
48524
|
for (const frame of outline.frames) {
|
|
48525
|
+
const styles = keys.get(frame.target) ?? new Set(libraries.forTarget(frame.target).textStyles.map((style) => style.key));
|
|
48526
|
+
keys.set(frame.target, styles);
|
|
47786
48527
|
const where = { feature: outline.feature, screen: outline.screen, frame: frame.name };
|
|
47787
48528
|
for (const text of frame.texts) {
|
|
47788
48529
|
if (text.styleKey === null) {
|
|
@@ -47792,7 +48533,7 @@ var font = ({ outlines, library }) => {
|
|
|
47792
48533
|
nodeId: text.nodeId,
|
|
47793
48534
|
message: "text outside a component uses no library text style"
|
|
47794
48535
|
});
|
|
47795
|
-
} else if (!
|
|
48536
|
+
} else if (!styles.has(text.styleKey)) {
|
|
47796
48537
|
findings.push({
|
|
47797
48538
|
check: "font",
|
|
47798
48539
|
...where,
|
|
@@ -47807,8 +48548,9 @@ var font = ({ outlines, library }) => {
|
|
|
47807
48548
|
};
|
|
47808
48549
|
|
|
47809
48550
|
// packages/zaku/dist/lib/domain/checks/freshness.js
|
|
47810
|
-
var freshness = ({ maps, outlines,
|
|
48551
|
+
var freshness = ({ config: config2, maps, outlines, flows, libraries }) => {
|
|
47811
48552
|
const digests = new Map(maps.map((loaded) => [loaded.map.feature, loaded.digest]));
|
|
48553
|
+
const graph = designGraph(config2);
|
|
47812
48554
|
const findings = [];
|
|
47813
48555
|
for (const outline of outlines) {
|
|
47814
48556
|
const where = { feature: outline.feature, screen: outline.screen };
|
|
@@ -47820,11 +48562,35 @@ var freshness = ({ maps, outlines, library }) => {
|
|
|
47820
48562
|
message: "the map changed after this outline was read; run zaku outline"
|
|
47821
48563
|
});
|
|
47822
48564
|
}
|
|
47823
|
-
|
|
48565
|
+
for (const [key, library] of Object.entries(libraries)) {
|
|
48566
|
+
const read = outline.libraryVersions[key] ?? (graph.legacy ? outline.libraryVersions[LEGACY_LIBRARY_VERSION] : void 0);
|
|
48567
|
+
if (read === library.version)
|
|
48568
|
+
continue;
|
|
47824
48569
|
findings.push({
|
|
47825
48570
|
check: "freshness",
|
|
47826
48571
|
...where,
|
|
47827
|
-
message: "the library changed after this outline was read; run zaku outline"
|
|
48572
|
+
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`
|
|
48573
|
+
});
|
|
48574
|
+
}
|
|
48575
|
+
}
|
|
48576
|
+
const drawn = new Map(outlines.flatMap((outline) => outline.frames.map((frame) => [`${outline.feature}/${outline.screen}
|
|
48577
|
+
${frame.name}`, frame])));
|
|
48578
|
+
for (const page of flows) {
|
|
48579
|
+
for (const copy2 of page.frames) {
|
|
48580
|
+
if (copy2.screen === null)
|
|
48581
|
+
continue;
|
|
48582
|
+
const source = drawn.get(`${copy2.screen}
|
|
48583
|
+
${copy2.name}`);
|
|
48584
|
+
if (source?.digest === void 0 || source.digest === copy2.digest)
|
|
48585
|
+
continue;
|
|
48586
|
+
const [feature = "", screen = ""] = copy2.screen.split("/");
|
|
48587
|
+
findings.push({
|
|
48588
|
+
check: "freshness",
|
|
48589
|
+
feature,
|
|
48590
|
+
screen,
|
|
48591
|
+
frame: copy2.name,
|
|
48592
|
+
nodeId: copy2.nodeId,
|
|
48593
|
+
message: `the copy on the flow page ${page.page} differs from the frame it copies; copy it again`
|
|
47828
48594
|
});
|
|
47829
48595
|
}
|
|
47830
48596
|
}
|
|
@@ -47832,13 +48598,43 @@ var freshness = ({ maps, outlines, library }) => {
|
|
|
47832
48598
|
};
|
|
47833
48599
|
|
|
47834
48600
|
// packages/zaku/dist/lib/domain/checks/library.js
|
|
47835
|
-
|
|
47836
|
-
|
|
47837
|
-
|
|
48601
|
+
function frameFindings(input2) {
|
|
48602
|
+
const libraries = checkLibraries(input2);
|
|
48603
|
+
if ("notRun" in libraries)
|
|
48604
|
+
return libraries;
|
|
48605
|
+
const { config: config2, maps, outlines } = input2;
|
|
48606
|
+
const library = libraries.all;
|
|
47838
48607
|
const bars = systemBarNames(config2);
|
|
47839
48608
|
const owned = outlines.flatMap((outline) => outline.frames.flatMap((frame) => frame.instances.filter((instance) => instance.local).map((instance) => instance.component)));
|
|
47840
48609
|
const names = /* @__PURE__ */ new Set([...library.components.map((component2) => component2.name), ...owned]);
|
|
47841
48610
|
const keys = new Set(library.components.flatMap((component2) => component2.variants.map((variant) => variant.key)));
|
|
48611
|
+
const graph = designGraph(config2);
|
|
48612
|
+
const owners = /* @__PURE__ */ new Map();
|
|
48613
|
+
for (const [key, snapshot] of Object.entries(input2.libraries)) {
|
|
48614
|
+
const holds = graph.libraries.find((candidate) => candidate.key === key)?.branches ?? [];
|
|
48615
|
+
for (const component2 of snapshot.components) {
|
|
48616
|
+
const branches = component2.branch ? [component2.branch] : holds;
|
|
48617
|
+
for (const variant of component2.variants)
|
|
48618
|
+
owners.set(variant.key, `${key}, a ${branches.join(" and ")} library`);
|
|
48619
|
+
}
|
|
48620
|
+
}
|
|
48621
|
+
for (const [key, kit] of Object.entries(input2.kits)) {
|
|
48622
|
+
for (const component2 of kit.components)
|
|
48623
|
+
owners.set(component2.key, `${key}, an ${kit.family} kit`);
|
|
48624
|
+
}
|
|
48625
|
+
const allowed2 = /* @__PURE__ */ new Map();
|
|
48626
|
+
const allowedFor = (target) => {
|
|
48627
|
+
const cached2 = allowed2.get(target.id);
|
|
48628
|
+
if (cached2)
|
|
48629
|
+
return cached2;
|
|
48630
|
+
const { libraries: own2, kits } = snapshotsFor(input2, target);
|
|
48631
|
+
const set2 = /* @__PURE__ */ new Set([
|
|
48632
|
+
...own2.flatMap((snapshot) => snapshot.components.flatMap((component2) => component2.variants.map((v) => v.key))),
|
|
48633
|
+
...kits.flatMap((kit) => kit.components.map((component2) => component2.key))
|
|
48634
|
+
]);
|
|
48635
|
+
allowed2.set(target.id, set2);
|
|
48636
|
+
return set2;
|
|
48637
|
+
};
|
|
47842
48638
|
const findings = [];
|
|
47843
48639
|
for (const { map: map2 } of maps) {
|
|
47844
48640
|
for (const [id2, screen] of Object.entries(map2.screens)) {
|
|
@@ -47858,8 +48654,22 @@ var libraryCheck = ({ config: config2, maps, outlines, library }) => {
|
|
|
47858
48654
|
for (const outline of outlines) {
|
|
47859
48655
|
for (const frame of outline.frames) {
|
|
47860
48656
|
const where = { feature: outline.feature, screen: outline.screen, frame: frame.name };
|
|
48657
|
+
const target = config2.targets.find((candidate) => candidate.id === frame.target);
|
|
47861
48658
|
for (const instance of frame.instances) {
|
|
47862
|
-
if (
|
|
48659
|
+
if (instance.local)
|
|
48660
|
+
continue;
|
|
48661
|
+
const owner = owners.get(instance.componentKey);
|
|
48662
|
+
if (target && owner && !allowedFor(target).has(instance.componentKey)) {
|
|
48663
|
+
const draws = owner.endsWith(" kit") ? `${target.family} kits` : graph.branchOf(target) ?? "no branch";
|
|
48664
|
+
findings.push({
|
|
48665
|
+
check: "library",
|
|
48666
|
+
...where,
|
|
48667
|
+
nodeId: instance.nodeId,
|
|
48668
|
+
message: `an instance of ${instance.component} comes from ${owner}; a ${target.name} frame draws from ${draws}`
|
|
48669
|
+
});
|
|
48670
|
+
continue;
|
|
48671
|
+
}
|
|
48672
|
+
if (!bars.has(instance.component) && !keys.has(instance.componentKey) && !owner) {
|
|
47863
48673
|
findings.push({
|
|
47864
48674
|
check: "library",
|
|
47865
48675
|
...where,
|
|
@@ -47879,6 +48689,82 @@ var libraryCheck = ({ config: config2, maps, outlines, library }) => {
|
|
|
47879
48689
|
}
|
|
47880
48690
|
}
|
|
47881
48691
|
return { findings };
|
|
48692
|
+
}
|
|
48693
|
+
function referable(snapshot) {
|
|
48694
|
+
return {
|
|
48695
|
+
variable: Object.values(snapshot.variableKeys ?? {}).flatMap((variable) => variable.local ? [variable.key] : []),
|
|
48696
|
+
"text style": snapshot.textStyles.map((style) => style.key),
|
|
48697
|
+
"effect style": (snapshot.effectStyles ?? []).map((style) => style.key),
|
|
48698
|
+
instance: snapshot.components.flatMap((component2) => [
|
|
48699
|
+
component2.key,
|
|
48700
|
+
...component2.variants.map((variant) => variant.key)
|
|
48701
|
+
])
|
|
48702
|
+
};
|
|
48703
|
+
}
|
|
48704
|
+
function referenceFindings(input2) {
|
|
48705
|
+
const graph = designGraph(input2.config);
|
|
48706
|
+
const findings = [];
|
|
48707
|
+
for (const [key, snapshot] of Object.entries(input2.libraries)) {
|
|
48708
|
+
if (!snapshot.variableKeys)
|
|
48709
|
+
continue;
|
|
48710
|
+
const bases = graph.closure(key).slice(1);
|
|
48711
|
+
const missing = bases.filter((base) => !input2.libraries[base] && !input2.kits[base]);
|
|
48712
|
+
if (missing.length > 0) {
|
|
48713
|
+
const paths = missing.map((base) => graph.kits.some((kit) => kit.key === base) ? `library/${base}/kit.json` : `library/${base}/index.json`);
|
|
48714
|
+
return { notRun: `${paths.join(", ")} ${paths.length === 1 ? "is" : "are"} missing` };
|
|
48715
|
+
}
|
|
48716
|
+
const allowed2 = {
|
|
48717
|
+
variable: /* @__PURE__ */ new Set(),
|
|
48718
|
+
"text style": /* @__PURE__ */ new Set(),
|
|
48719
|
+
"effect style": /* @__PURE__ */ new Set(),
|
|
48720
|
+
instance: new Set(snapshot.localComponents ?? [])
|
|
48721
|
+
};
|
|
48722
|
+
for (const from of [key, ...bases]) {
|
|
48723
|
+
const library = input2.libraries[from];
|
|
48724
|
+
if (library)
|
|
48725
|
+
for (const [kind, keys] of Object.entries(referable(library)))
|
|
48726
|
+
for (const ref of keys)
|
|
48727
|
+
allowed2[kind].add(ref);
|
|
48728
|
+
for (const component2 of input2.kits[from]?.components ?? [])
|
|
48729
|
+
allowed2.instance.add(component2.key);
|
|
48730
|
+
}
|
|
48731
|
+
const extended2 = bases.length > 0 ? `from ${bases.join(", ")}` : "from a library it extends, and it extends none";
|
|
48732
|
+
for (const component2 of snapshot.components) {
|
|
48733
|
+
for (const variant of component2.variants) {
|
|
48734
|
+
for (const item of variant.modes[0]?.items ?? []) {
|
|
48735
|
+
const refs = [
|
|
48736
|
+
...(item.variableIds ?? []).map((id2) => [
|
|
48737
|
+
"variable",
|
|
48738
|
+
snapshot.variableKeys?.[id2]?.key ?? id2
|
|
48739
|
+
]),
|
|
48740
|
+
...item.textStyleKey ? [["text style", item.textStyleKey]] : [],
|
|
48741
|
+
...item.effectStyleKey ? [["effect style", item.effectStyleKey]] : [],
|
|
48742
|
+
...item.componentKey ? [["instance", item.componentKey]] : []
|
|
48743
|
+
];
|
|
48744
|
+
for (const [kind, ref] of refs) {
|
|
48745
|
+
if (allowed2[kind].has(ref))
|
|
48746
|
+
continue;
|
|
48747
|
+
findings.push({
|
|
48748
|
+
check: "library",
|
|
48749
|
+
nodeId: item.nodeId,
|
|
48750
|
+
field: "references",
|
|
48751
|
+
message: `${key}: ${component2.name} ${variant.name} ${item.path || "(root)"}: ${kind} ${ref} is neither the library's own nor ${extended2}`
|
|
48752
|
+
});
|
|
48753
|
+
}
|
|
48754
|
+
}
|
|
48755
|
+
}
|
|
48756
|
+
}
|
|
48757
|
+
}
|
|
48758
|
+
return { findings };
|
|
48759
|
+
}
|
|
48760
|
+
var libraryCheck = (input2) => {
|
|
48761
|
+
const frames = frameFindings(input2);
|
|
48762
|
+
if ("notRun" in frames)
|
|
48763
|
+
return frames;
|
|
48764
|
+
const references = referenceFindings(input2);
|
|
48765
|
+
if ("notRun" in references)
|
|
48766
|
+
return references;
|
|
48767
|
+
return { findings: [...frames.findings, ...references.findings] };
|
|
47882
48768
|
};
|
|
47883
48769
|
|
|
47884
48770
|
// packages/zaku/dist/lib/domain/checks/navigation.js
|
|
@@ -47949,7 +48835,11 @@ var ALLOWED_OVERRIDES = /* @__PURE__ */ new Set([
|
|
|
47949
48835
|
"name",
|
|
47950
48836
|
"componentProperties",
|
|
47951
48837
|
"componentPropertyReferences",
|
|
47952
|
-
"exposedInstances"
|
|
48838
|
+
"exposedInstances",
|
|
48839
|
+
"reactions",
|
|
48840
|
+
"transitionNodeID",
|
|
48841
|
+
"transitionDuration",
|
|
48842
|
+
"transitionEasing"
|
|
47953
48843
|
]);
|
|
47954
48844
|
var SIZING_MODES = /* @__PURE__ */ new Set(["primaryAxisSizingMode", "counterAxisSizingMode"]);
|
|
47955
48845
|
function componentSized(field, size2, main2) {
|
|
@@ -47963,9 +48853,12 @@ function stretches(sizing) {
|
|
|
47963
48853
|
function insideSwap(instance, nodeId) {
|
|
47964
48854
|
return instance.nested.some((nested) => nodeId.startsWith(`${nested.nodeId};`) && instance.swaps.includes(nested.componentKey));
|
|
47965
48855
|
}
|
|
47966
|
-
var overrides = (
|
|
47967
|
-
|
|
47968
|
-
|
|
48856
|
+
var overrides = (input2) => {
|
|
48857
|
+
const libraries = checkLibraries(input2);
|
|
48858
|
+
if ("notRun" in libraries)
|
|
48859
|
+
return libraries;
|
|
48860
|
+
const { outlines } = input2;
|
|
48861
|
+
const library = libraries.all;
|
|
47969
48862
|
const nestedOf = /* @__PURE__ */ new Map();
|
|
47970
48863
|
const componentOf = /* @__PURE__ */ new Map();
|
|
47971
48864
|
for (const component2 of library.components) {
|
|
@@ -48026,18 +48919,58 @@ var overrides = ({ outlines, library }) => {
|
|
|
48026
48919
|
return { findings };
|
|
48027
48920
|
};
|
|
48028
48921
|
|
|
48922
|
+
// packages/zaku/dist/lib/domain/flows.js
|
|
48923
|
+
function flowsOf(maps) {
|
|
48924
|
+
const index = indexScreens(maps);
|
|
48925
|
+
const flows = [];
|
|
48926
|
+
for (const root of index.values()) {
|
|
48927
|
+
if (!root.screen.root)
|
|
48928
|
+
continue;
|
|
48929
|
+
const screens = [root];
|
|
48930
|
+
for (let at = 0; at < screens.length; at += 1) {
|
|
48931
|
+
const from = screens[at];
|
|
48932
|
+
if (!from)
|
|
48933
|
+
continue;
|
|
48934
|
+
for (const exit of from.screen.exits) {
|
|
48935
|
+
const next = index.get(qualify(exit.to, from.feature));
|
|
48936
|
+
if (next && !screens.includes(next))
|
|
48937
|
+
screens.push(next);
|
|
48938
|
+
}
|
|
48939
|
+
}
|
|
48940
|
+
flows.push({ root, screens });
|
|
48941
|
+
}
|
|
48942
|
+
return flows;
|
|
48943
|
+
}
|
|
48944
|
+
|
|
48029
48945
|
// packages/zaku/dist/lib/domain/checks/prototype.js
|
|
48030
|
-
|
|
48031
|
-
if (
|
|
48032
|
-
return
|
|
48946
|
+
function legacyScreens(input2) {
|
|
48947
|
+
if (input2.flows.length === 0)
|
|
48948
|
+
return input2.outlines;
|
|
48949
|
+
const byScreen = /* @__PURE__ */ new Map();
|
|
48950
|
+
for (const page of input2.flows) {
|
|
48951
|
+
for (const frame of page.frames) {
|
|
48952
|
+
if (frame.screen === null)
|
|
48953
|
+
continue;
|
|
48954
|
+
const [feature = "", screen = ""] = frame.screen.split("/");
|
|
48955
|
+
const entry = byScreen.get(frame.screen) ?? { feature, screen, frames: [] };
|
|
48956
|
+
entry.frames.push(frame);
|
|
48957
|
+
byScreen.set(frame.screen, entry);
|
|
48958
|
+
}
|
|
48959
|
+
}
|
|
48960
|
+
return [...byScreen.values()];
|
|
48961
|
+
}
|
|
48962
|
+
function legacyFindings(input2) {
|
|
48963
|
+
const screens = legacyScreens(input2);
|
|
48964
|
+
if (screens.length === 0)
|
|
48965
|
+
return [];
|
|
48033
48966
|
const screenOfFrame = /* @__PURE__ */ new Map();
|
|
48034
|
-
const outlineOf = new Map(
|
|
48035
|
-
for (const outline of
|
|
48967
|
+
const outlineOf = new Map(screens.map((outline) => [`${outline.feature}/${outline.screen}`, outline]));
|
|
48968
|
+
for (const outline of screens) {
|
|
48036
48969
|
for (const frame of outline.frames)
|
|
48037
48970
|
screenOfFrame.set(frame.nodeId, `${outline.feature}/${outline.screen}`);
|
|
48038
48971
|
}
|
|
48039
48972
|
const findings = [];
|
|
48040
|
-
for (const { map: map2 } of maps) {
|
|
48973
|
+
for (const { map: map2 } of input2.maps) {
|
|
48041
48974
|
for (const [id2, screen] of Object.entries(map2.screens)) {
|
|
48042
48975
|
const outline = outlineOf.get(`${map2.feature}/${id2}`);
|
|
48043
48976
|
if (!outline)
|
|
@@ -48074,8 +49007,64 @@ var prototype = ({ maps, outlines }) => {
|
|
|
48074
49007
|
}
|
|
48075
49008
|
}
|
|
48076
49009
|
}
|
|
48077
|
-
return
|
|
48078
|
-
}
|
|
49010
|
+
return findings;
|
|
49011
|
+
}
|
|
49012
|
+
function flowFindings(input2) {
|
|
49013
|
+
const prototypes = new Set(designGraph(input2.config).prototypes.map((file2) => file2.key));
|
|
49014
|
+
const findings = [];
|
|
49015
|
+
for (const flow of flowsOf(input2.maps)) {
|
|
49016
|
+
const { root } = flow;
|
|
49017
|
+
const title = root.screen.title;
|
|
49018
|
+
const keyOf = (ref) => `${ref.feature}/${ref.id}`;
|
|
49019
|
+
const pages = input2.flows.filter((page) => page.page === title && prototypes.has(page.source));
|
|
49020
|
+
if (pages.length === 0) {
|
|
49021
|
+
findings.push({
|
|
49022
|
+
check: "prototype",
|
|
49023
|
+
feature: root.feature,
|
|
49024
|
+
screen: root.id,
|
|
49025
|
+
message: `no flow page is named ${title}`
|
|
49026
|
+
});
|
|
49027
|
+
continue;
|
|
49028
|
+
}
|
|
49029
|
+
const inFlow = new Set(flow.screens.map(keyOf));
|
|
49030
|
+
for (const page of pages) {
|
|
49031
|
+
const screenOf = new Map(page.frames.map((frame) => [frame.nodeId, frame.screen]));
|
|
49032
|
+
const first = root.screen.states[0];
|
|
49033
|
+
if (!page.frames.some((frame) => frame.screen === keyOf(root) && frame.state === first && frame.start))
|
|
49034
|
+
findings.push({
|
|
49035
|
+
check: "prototype",
|
|
49036
|
+
feature: root.feature,
|
|
49037
|
+
screen: root.id,
|
|
49038
|
+
message: `the flow page ${title} does not start on ${title}'s first state`
|
|
49039
|
+
});
|
|
49040
|
+
for (const ref of flow.screens) {
|
|
49041
|
+
const where = { check: "prototype", feature: ref.feature, screen: ref.id };
|
|
49042
|
+
const copies = page.frames.filter((frame) => frame.screen === keyOf(ref));
|
|
49043
|
+
for (const exit of ref.screen.exits) {
|
|
49044
|
+
const target = qualify(exit.to, ref.feature);
|
|
49045
|
+
if (!inFlow.has(target))
|
|
49046
|
+
continue;
|
|
49047
|
+
const connected = copies.some((frame) => frame.links.some((link) => link.to !== "back" && screenOf.get(link.to.nodeId) === target));
|
|
49048
|
+
if (!connected)
|
|
49049
|
+
findings.push({
|
|
49050
|
+
...where,
|
|
49051
|
+
field: "exits",
|
|
49052
|
+
message: `on the flow page ${title}, the exit to ${exit.to} (${exit.via}) has no connection`
|
|
49053
|
+
});
|
|
49054
|
+
}
|
|
49055
|
+
if (ref !== root && copies.length > 0 && !copies.some((frame) => frame.links.some((link) => link.to === "back")))
|
|
49056
|
+
findings.push({
|
|
49057
|
+
...where,
|
|
49058
|
+
message: `on the flow page ${title}, a screen that is not the root has no Back action`
|
|
49059
|
+
});
|
|
49060
|
+
}
|
|
49061
|
+
}
|
|
49062
|
+
}
|
|
49063
|
+
return findings;
|
|
49064
|
+
}
|
|
49065
|
+
var prototype = (input2) => ({
|
|
49066
|
+
findings: designGraph(input2.config).prototypes.length > 0 ? flowFindings(input2) : legacyFindings(input2)
|
|
49067
|
+
});
|
|
48079
49068
|
|
|
48080
49069
|
// packages/zaku/dist/lib/domain/checks/recipe.js
|
|
48081
49070
|
function propsLabel(props) {
|
|
@@ -48155,9 +49144,14 @@ function comparePart(at, part) {
|
|
|
48155
49144
|
});
|
|
48156
49145
|
}
|
|
48157
49146
|
}
|
|
48158
|
-
var recipe = (
|
|
48159
|
-
|
|
48160
|
-
|
|
49147
|
+
var recipe = (input2) => {
|
|
49148
|
+
const { config: config2, recipe: doc } = input2;
|
|
49149
|
+
const libraries = checkLibraries(input2);
|
|
49150
|
+
if ("notRun" in libraries)
|
|
49151
|
+
return doc ? libraries : { notRun: `recipe.json or ${libraries.notRun}` };
|
|
49152
|
+
if (!doc)
|
|
49153
|
+
return { notRun: "recipe.json is missing" };
|
|
49154
|
+
const library = libraries.all;
|
|
48161
49155
|
const findings = [];
|
|
48162
49156
|
for (const code of doc.components) {
|
|
48163
49157
|
const component2 = library.components.find((candidate) => candidate.name === code.name);
|
|
@@ -48248,9 +49242,12 @@ var MIN_TARGET = {
|
|
|
48248
49242
|
function controlsOf(frame) {
|
|
48249
49243
|
return frame.instances.flatMap((instance) => [instance, ...instance.nested].flatMap((control) => control.interactive && control.bounds ? [{ nodeId: control.nodeId, componentKey: control.componentKey, bounds: control.bounds }] : []));
|
|
48250
49244
|
}
|
|
48251
|
-
var targetSize = (
|
|
48252
|
-
|
|
48253
|
-
|
|
49245
|
+
var targetSize = (input2) => {
|
|
49246
|
+
const libraries = checkLibraries(input2);
|
|
49247
|
+
if ("notRun" in libraries)
|
|
49248
|
+
return libraries;
|
|
49249
|
+
const { config: config2, outlines } = input2;
|
|
49250
|
+
const library = libraries.all;
|
|
48254
49251
|
const presetHeight = /* @__PURE__ */ new Map();
|
|
48255
49252
|
for (const component2 of library.components) {
|
|
48256
49253
|
for (const variant of component2.variants) {
|
|
@@ -48332,9 +49329,14 @@ function rgbaOf(token) {
|
|
|
48332
49329
|
const [r, g, b] = token.$value.components;
|
|
48333
49330
|
return { r, g, b, a: token.$value.alpha };
|
|
48334
49331
|
}
|
|
48335
|
-
var tokensCheck = (
|
|
48336
|
-
|
|
48337
|
-
|
|
49332
|
+
var tokensCheck = (input2) => {
|
|
49333
|
+
const { config: config2, tokens } = input2;
|
|
49334
|
+
const libraries = checkLibraries(input2);
|
|
49335
|
+
if ("notRun" in libraries)
|
|
49336
|
+
return libraries;
|
|
49337
|
+
if (!tokens)
|
|
49338
|
+
return { notRun: "tokens.json is missing" };
|
|
49339
|
+
const library = libraries.all;
|
|
48338
49340
|
const sets = tokenSets(tokens);
|
|
48339
49341
|
const findings = [];
|
|
48340
49342
|
for (const [scheme, set2] of [
|
|
@@ -48638,13 +49640,25 @@ async function loadDesign(root) {
|
|
|
48638
49640
|
message: `two screens share the title ${title}; a frame name could not tell them apart`
|
|
48639
49641
|
});
|
|
48640
49642
|
}
|
|
48641
|
-
const { outlines, unmapped, errors: outlineErrors } = await loadOutlines(paths.outline);
|
|
49643
|
+
const { outlines, flows, unmapped, errors: outlineErrors } = await loadOutlines(paths.outline);
|
|
48642
49644
|
findings.push(...outlineErrors.map(schemaFinding));
|
|
48643
|
-
const
|
|
49645
|
+
const { libraries, kits, errors: snapshotErrors } = await readDesignSnapshots(paths, config2);
|
|
49646
|
+
findings.push(...snapshotErrors.map(schemaFinding));
|
|
48644
49647
|
const tokens = await optional3(() => readOptionalDesignFile(paths.tokens, tokenDocumentSchema), findings);
|
|
48645
49648
|
const recipe2 = await optional3(() => readOptionalDesignFile(paths.recipe, recipeDocumentSchema), findings);
|
|
48646
49649
|
return {
|
|
48647
|
-
input: {
|
|
49650
|
+
input: {
|
|
49651
|
+
config: config2,
|
|
49652
|
+
maps,
|
|
49653
|
+
outlines,
|
|
49654
|
+
flows,
|
|
49655
|
+
unmapped: unmapped?.frames ?? [],
|
|
49656
|
+
productComponents: unmapped?.components ?? [],
|
|
49657
|
+
libraries,
|
|
49658
|
+
kits,
|
|
49659
|
+
tokens,
|
|
49660
|
+
recipe: recipe2
|
|
49661
|
+
},
|
|
48648
49662
|
findings
|
|
48649
49663
|
};
|
|
48650
49664
|
}
|
|
@@ -48679,6 +49693,7 @@ function refusalOf(error62) {
|
|
|
48679
49693
|
}
|
|
48680
49694
|
if (error62 instanceof FigmaFileKeyMissing) return { code: 3, line: error62.message };
|
|
48681
49695
|
if (error62 instanceof FigmaTokenMissing) return { code: 3, line: error62.message };
|
|
49696
|
+
if (error62 instanceof LibraryKeyMissing) return { code: 3, line: error62.message };
|
|
48682
49697
|
if (error62 instanceof RecipePageFailed) return { code: 2, line: `zaku recipe: ${error62.message}` };
|
|
48683
49698
|
return null;
|
|
48684
49699
|
}
|
|
@@ -58368,11 +59383,11 @@ var StdioServerTransport = class {
|
|
|
58368
59383
|
// apps/zaku-cli/src/mcp/server.ts
|
|
58369
59384
|
import { mkdir as mkdir5 } from "node:fs/promises";
|
|
58370
59385
|
import { tmpdir } from "node:os";
|
|
58371
|
-
import { join as
|
|
59386
|
+
import { join as join11 } from "node:path";
|
|
58372
59387
|
|
|
58373
59388
|
// apps/zaku-cli/src/mcp/screenshots.ts
|
|
58374
59389
|
import { readdir as readdir4, rm as rm3, stat } from "node:fs/promises";
|
|
58375
|
-
import { join as
|
|
59390
|
+
import { join as join9 } from "node:path";
|
|
58376
59391
|
var KEPT_MS = 24 * 60 * 60 * 1e3;
|
|
58377
59392
|
async function pruneScreenshots(dir, now) {
|
|
58378
59393
|
let names;
|
|
@@ -58382,7 +59397,7 @@ async function pruneScreenshots(dir, now) {
|
|
|
58382
59397
|
return;
|
|
58383
59398
|
}
|
|
58384
59399
|
for (const name of names.filter((entry) => entry.endsWith(".png"))) {
|
|
58385
|
-
const path2 =
|
|
59400
|
+
const path2 = join9(dir, name);
|
|
58386
59401
|
const written = await stat(path2).then(
|
|
58387
59402
|
(stats) => stats.mtimeMs,
|
|
58388
59403
|
() => now
|
|
@@ -58393,8 +59408,8 @@ async function pruneScreenshots(dir, now) {
|
|
|
58393
59408
|
|
|
58394
59409
|
// apps/zaku-cli/src/mcp/tools.ts
|
|
58395
59410
|
import { writeFile as writeFile5 } from "node:fs/promises";
|
|
58396
|
-
import { join as
|
|
58397
|
-
var
|
|
59411
|
+
import { join as join10 } from "node:path";
|
|
59412
|
+
var fileKey2 = external_exports.string().min(1).regex(/^[0-9a-zA-Z]{22,128}$/).describe(
|
|
58398
59413
|
"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."
|
|
58399
59414
|
);
|
|
58400
59415
|
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.";
|
|
@@ -58406,7 +59421,7 @@ function registerFigmaTools(server, bridge, options) {
|
|
|
58406
59421
|
inputSchema: external_exports.object({
|
|
58407
59422
|
code: external_exports.string().max(5e4).describe("JavaScript code to execute. Has access to the `figma` global (Figma Plugin API)"),
|
|
58408
59423
|
description: external_exports.string().max(2e3).describe("A concise description of what the code aims to do"),
|
|
58409
|
-
fileKey,
|
|
59424
|
+
fileKey: fileKey2,
|
|
58410
59425
|
skillNames: external_exports.string().optional().describe("A comma-separated list of Figma skill names being followed, if any.")
|
|
58411
59426
|
}).strict()
|
|
58412
59427
|
},
|
|
@@ -58424,7 +59439,7 @@ function registerFigmaTools(server, bridge, options) {
|
|
|
58424
59439
|
inputSchema: external_exports.object({
|
|
58425
59440
|
contentsOnly: external_exports.boolean().optional().describe("When true, renders the node in isolation. Defaults to false."),
|
|
58426
59441
|
enableBase64Response: external_exports.boolean().default(false).describe("When true, the response also includes the screenshot inline as a base64-encoded image entry."),
|
|
58427
|
-
fileKey,
|
|
59442
|
+
fileKey: fileKey2,
|
|
58428
59443
|
maxDimension: external_exports.number().int().max(65536).default(1024).describe("Maximum pixel size of the longer edge of the rendered screenshot. Defaults to 1024."),
|
|
58429
59444
|
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".')
|
|
58430
59445
|
}).strict()
|
|
@@ -58437,7 +59452,7 @@ function registerFigmaTools(server, bridge, options) {
|
|
|
58437
59452
|
options.timeoutMs
|
|
58438
59453
|
);
|
|
58439
59454
|
if (!answer.ok) return { isError: true, content: [{ type: "text", text: answer.error }] };
|
|
58440
|
-
const path2 =
|
|
59455
|
+
const path2 = join10(options.imageDir, `${id2.replace(":", "-")}-${Date.now()}.png`);
|
|
58441
59456
|
await writeFile5(path2, Buffer.from(answer.png, "base64"));
|
|
58442
59457
|
const text = JSON.stringify({
|
|
58443
59458
|
path: path2,
|
|
@@ -58463,7 +59478,7 @@ async function serveMcp(log) {
|
|
|
58463
59478
|
log(
|
|
58464
59479
|
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}`
|
|
58465
59480
|
);
|
|
58466
|
-
const imageDir =
|
|
59481
|
+
const imageDir = join11(tmpdir(), "zaku-screenshots");
|
|
58467
59482
|
await mkdir5(imageDir, { recursive: true });
|
|
58468
59483
|
await pruneScreenshots(imageDir, Date.now());
|
|
58469
59484
|
const server = new McpServer({ name: "zaku", version: "1" });
|
|
@@ -58480,7 +59495,7 @@ async function serveMcp(log) {
|
|
|
58480
59495
|
|
|
58481
59496
|
// apps/zaku-cli/src/cli.ts
|
|
58482
59497
|
var USE_FIGMA_CODE_LIMIT = 5e4;
|
|
58483
|
-
var USAGE = "usage: zaku <check|outline|tokens|recipe|library|rules|budget|schema|mcp> [--root docs/design]";
|
|
59498
|
+
var USAGE = "usage: zaku <check|outline|tokens|recipe|library|libraries|rules|budget|schema|mcp> [--root docs/design]";
|
|
58484
59499
|
async function sendOrRefuse(cli, io, finish, command) {
|
|
58485
59500
|
try {
|
|
58486
59501
|
return await cli.bus.send(command);
|
|
@@ -58498,6 +59513,14 @@ async function recordRestCalls(cli, io) {
|
|
|
58498
59513
|
const { seat, run } = seatAndRun(io.env);
|
|
58499
59514
|
await cli.bus.send(new RecordBudgetCalls({ day: today(clock.now()), seat, run, kind: "rest", count }));
|
|
58500
59515
|
}
|
|
59516
|
+
var librariesCommand = (program2, io, finish) => {
|
|
59517
|
+
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) => {
|
|
59518
|
+
const paths = designPaths(resolve2(io.cwd, options.root));
|
|
59519
|
+
const config2 = await readDesignFile(paths.config, zakuConfigSchema);
|
|
59520
|
+
for (const line of printGraph(config2, await readDesignSnapshots(paths, config2))) io.out(line);
|
|
59521
|
+
finish(0);
|
|
59522
|
+
});
|
|
59523
|
+
};
|
|
58501
59524
|
var schemaCommand = (program2, io, finish, cli) => {
|
|
58502
59525
|
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) => {
|
|
58503
59526
|
const written = await cli.bus.send(new WriteSchemas({ out: resolve2(io.cwd, options.out) }));
|
|
@@ -58524,7 +59547,7 @@ var checkCommand = (program2, io, finish) => {
|
|
|
58524
59547
|
});
|
|
58525
59548
|
};
|
|
58526
59549
|
async function productPlaywright(cwd) {
|
|
58527
|
-
const require2 = createRequire(
|
|
59550
|
+
const require2 = createRequire(join12(cwd, "package.json"));
|
|
58528
59551
|
let resolved;
|
|
58529
59552
|
try {
|
|
58530
59553
|
resolved = require2.resolve("playwright");
|
|
@@ -58536,7 +59559,7 @@ async function productPlaywright(cwd) {
|
|
|
58536
59559
|
}
|
|
58537
59560
|
function fromProductTree(cwd, resolved) {
|
|
58538
59561
|
for (let dir = resolve2(cwd); ; dir = dirname4(dir)) {
|
|
58539
|
-
if (resolved.startsWith(
|
|
59562
|
+
if (resolved.startsWith(join12(dir, "node_modules") + sep)) return true;
|
|
58540
59563
|
if (dirname4(dir) === dir) return false;
|
|
58541
59564
|
}
|
|
58542
59565
|
}
|
|
@@ -58661,13 +59684,26 @@ var libraryCommand = (program2, io, finish, cli) => {
|
|
|
58661
59684
|
finish(0);
|
|
58662
59685
|
}
|
|
58663
59686
|
);
|
|
58664
|
-
library.command("save").description(
|
|
59687
|
+
library.command("save").description(
|
|
59688
|
+
"write a library's snapshot from its components over Figma REST, joined to the variables export, or a kit's published components"
|
|
59689
|
+
).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(
|
|
58665
59690
|
"--input <variables.json>",
|
|
58666
59691
|
"what use_figma returned for zaku library script; once per page export for a library in the product file",
|
|
58667
59692
|
(value, previous = []) => [...previous, value]
|
|
58668
59693
|
).action(async (options) => {
|
|
58669
59694
|
const root = resolve2(io.cwd, options.root);
|
|
58670
|
-
|
|
59695
|
+
const config2 = await readDesignFile(designPaths(root).config, zakuConfigSchema);
|
|
59696
|
+
let target;
|
|
59697
|
+
try {
|
|
59698
|
+
target = librarySaveTarget(config2, options.key);
|
|
59699
|
+
} catch (error62) {
|
|
59700
|
+
const refusal = refusalOf(error62);
|
|
59701
|
+
if (!refusal) throw error62;
|
|
59702
|
+
io.err(refusal.line);
|
|
59703
|
+
finish(refusal.code);
|
|
59704
|
+
return;
|
|
59705
|
+
}
|
|
59706
|
+
if (target.kind === "library" && (!options.input || options.input.length === 0)) {
|
|
58671
59707
|
io.err("zaku library save needs --input, the variables use_figma returned for zaku library script");
|
|
58672
59708
|
finish(3);
|
|
58673
59709
|
return;
|
|
@@ -58677,26 +59713,36 @@ var libraryCommand = (program2, io, finish, cli) => {
|
|
|
58677
59713
|
finish(3);
|
|
58678
59714
|
return;
|
|
58679
59715
|
}
|
|
58680
|
-
const part = mergeParts(
|
|
59716
|
+
const part = target.kind === "library" ? mergeParts(
|
|
58681
59717
|
await Promise.all(
|
|
58682
|
-
options.input.map(
|
|
59718
|
+
(options.input ?? []).map(
|
|
58683
59719
|
async (input2) => parseDesignFile(input2, await readFile6(resolve2(io.cwd, input2), "utf8"), variablePartSchema)
|
|
58684
59720
|
)
|
|
58685
59721
|
)
|
|
58686
|
-
);
|
|
59722
|
+
) : void 0;
|
|
58687
59723
|
try {
|
|
58688
|
-
const
|
|
58689
|
-
new SaveLibrary({
|
|
59724
|
+
const saved = await cli.bus.send(
|
|
59725
|
+
new SaveLibrary({
|
|
59726
|
+
root,
|
|
59727
|
+
...options.key !== void 0 ? { key: options.key } : {},
|
|
59728
|
+
...part ? { part } : {}
|
|
59729
|
+
})
|
|
58690
59730
|
);
|
|
59731
|
+
if (saved.kind === "kit") {
|
|
59732
|
+
io.out(`wrote ${saved.dir}/kit.json: ${saved.kit.components.length} components`);
|
|
59733
|
+
finish(0);
|
|
59734
|
+
return;
|
|
59735
|
+
}
|
|
59736
|
+
const { snapshot, written, unchanged, removed } = saved;
|
|
58691
59737
|
if (snapshot.components.length === 0) {
|
|
58692
59738
|
io.err(
|
|
58693
|
-
|
|
59739
|
+
`${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`
|
|
58694
59740
|
);
|
|
58695
59741
|
finish(1);
|
|
58696
59742
|
return;
|
|
58697
59743
|
}
|
|
58698
59744
|
io.out(
|
|
58699
|
-
`wrote
|
|
59745
|
+
`wrote ${saved.dir}/: ${snapshot.components.length} components at version ${snapshot.version}; ${written.length} component files written, ${unchanged} unchanged, ${removed.length} removed`
|
|
58700
59746
|
);
|
|
58701
59747
|
finish(0);
|
|
58702
59748
|
} finally {
|
|
@@ -58706,7 +59752,7 @@ var libraryCommand = (program2, io, finish, cli) => {
|
|
|
58706
59752
|
};
|
|
58707
59753
|
var rulesCommand = (program2, io, finish) => {
|
|
58708
59754
|
const rules = program2.command("rules").description("zaku's rule checks, for a run that reaches Figma through use_figma");
|
|
58709
|
-
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) => {
|
|
59755
|
+
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) => {
|
|
58710
59756
|
if (options.page === void 0 === (options.node === void 0)) {
|
|
58711
59757
|
io.err("zaku rules script needs --page or --node, one of them");
|
|
58712
59758
|
finish(3);
|
|
@@ -58714,7 +59760,17 @@ var rulesCommand = (program2, io, finish) => {
|
|
|
58714
59760
|
}
|
|
58715
59761
|
const config2 = await readDesignFile(designPaths(resolve2(io.cwd, options.root)).config, zakuConfigSchema);
|
|
58716
59762
|
const scope = options.node !== void 0 ? { nodeId: options.node } : { page: options.page };
|
|
58717
|
-
const
|
|
59763
|
+
const graph = designGraph(config2);
|
|
59764
|
+
const file2 = options.key === void 0 ? graph.libraries.length === 1 ? graph.libraries[0] : void 0 : graph.libraries.find((library2) => library2.key === options.key);
|
|
59765
|
+
if (options.key !== void 0 && !file2) {
|
|
59766
|
+
io.err(
|
|
59767
|
+
`zaku rules script: ${options.key} is not a library zaku.yaml lists; name one with --key: ${graph.libraries.map((library2) => library2.key).join(", ")}`
|
|
59768
|
+
);
|
|
59769
|
+
finish(3);
|
|
59770
|
+
return;
|
|
59771
|
+
}
|
|
59772
|
+
const branches = file2?.branches ?? [];
|
|
59773
|
+
const check2 = `await zakuRulesLib.zakuRules(figma, ${JSON.stringify({ scope, copy: resolveCopy(config2.copy), ...branches.length > 1 ? { branches } : {} })})`;
|
|
58718
59774
|
const library = await runners.rulesLibrary();
|
|
58719
59775
|
if (options.after === void 0) {
|
|
58720
59776
|
io.out(`${library}
|
|
@@ -58753,6 +59809,7 @@ var COMMANDS = [
|
|
|
58753
59809
|
recipeCommand,
|
|
58754
59810
|
budgetCommand,
|
|
58755
59811
|
schemaCommand,
|
|
59812
|
+
librariesCommand,
|
|
58756
59813
|
mcpCommand
|
|
58757
59814
|
];
|
|
58758
59815
|
async function main(argv, io) {
|