@zeroxsolutions/zaku 0.0.4 → 0.2.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/README.md +9 -1
- package/dist/rules.js +1 -1
- package/dist/zaku.mjs +1069 -635
- package/package.json +3 -3
package/dist/zaku.mjs
CHANGED
|
@@ -1187,11 +1187,11 @@ function __metadata(metadataKey, metadataValue) {
|
|
|
1187
1187
|
}
|
|
1188
1188
|
function __awaiter(thisArg, _arguments, P, generator) {
|
|
1189
1189
|
function adopt(value) {
|
|
1190
|
-
return value instanceof P ? value : new P(function(
|
|
1191
|
-
|
|
1190
|
+
return value instanceof P ? value : new P(function(resolve4) {
|
|
1191
|
+
resolve4(value);
|
|
1192
1192
|
});
|
|
1193
1193
|
}
|
|
1194
|
-
return new (P || (P = Promise))(function(
|
|
1194
|
+
return new (P || (P = Promise))(function(resolve4, reject) {
|
|
1195
1195
|
function fulfilled(value) {
|
|
1196
1196
|
try {
|
|
1197
1197
|
step(generator.next(value));
|
|
@@ -1207,7 +1207,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
1207
1207
|
}
|
|
1208
1208
|
}
|
|
1209
1209
|
function step(result) {
|
|
1210
|
-
result.done ?
|
|
1210
|
+
result.done ? resolve4(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
1211
1211
|
}
|
|
1212
1212
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
1213
1213
|
});
|
|
@@ -1385,14 +1385,14 @@ function __asyncValues(o) {
|
|
|
1385
1385
|
}, i);
|
|
1386
1386
|
function verb(n) {
|
|
1387
1387
|
i[n] = o[n] && function(v) {
|
|
1388
|
-
return new Promise(function(
|
|
1389
|
-
v = o[n](v), settle2(
|
|
1388
|
+
return new Promise(function(resolve4, reject) {
|
|
1389
|
+
v = o[n](v), settle2(resolve4, reject, v.done, v.value);
|
|
1390
1390
|
});
|
|
1391
1391
|
};
|
|
1392
1392
|
}
|
|
1393
|
-
function settle2(
|
|
1393
|
+
function settle2(resolve4, reject, d, v) {
|
|
1394
1394
|
Promise.resolve(v).then(function(v2) {
|
|
1395
|
-
|
|
1395
|
+
resolve4({ value: v2, done: d });
|
|
1396
1396
|
}, reject);
|
|
1397
1397
|
}
|
|
1398
1398
|
}
|
|
@@ -2217,7 +2217,7 @@ var require_injectable = __commonJS({
|
|
|
2217
2217
|
var reflection_helpers_1 = require_reflection_helpers();
|
|
2218
2218
|
var dependency_container_1 = require_dependency_container();
|
|
2219
2219
|
var dependency_container_2 = require_dependency_container();
|
|
2220
|
-
function
|
|
2220
|
+
function injectable11(options) {
|
|
2221
2221
|
return function(target) {
|
|
2222
2222
|
dependency_container_1.typeInfo.set(target, reflection_helpers_1.getParamInfo(target));
|
|
2223
2223
|
if (options && options.token) {
|
|
@@ -2231,7 +2231,7 @@ var require_injectable = __commonJS({
|
|
|
2231
2231
|
}
|
|
2232
2232
|
};
|
|
2233
2233
|
}
|
|
2234
|
-
exports.default =
|
|
2234
|
+
exports.default = injectable11;
|
|
2235
2235
|
}
|
|
2236
2236
|
});
|
|
2237
2237
|
|
|
@@ -16461,7 +16461,7 @@ var require_compile = __commonJS({
|
|
|
16461
16461
|
const schOrFunc = root.refs[ref];
|
|
16462
16462
|
if (schOrFunc)
|
|
16463
16463
|
return schOrFunc;
|
|
16464
|
-
let _sch =
|
|
16464
|
+
let _sch = resolve4.call(this, root, ref);
|
|
16465
16465
|
if (_sch === void 0) {
|
|
16466
16466
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
16467
16467
|
const { schemaId } = this.opts;
|
|
@@ -16488,7 +16488,7 @@ var require_compile = __commonJS({
|
|
|
16488
16488
|
function sameSchemaEnv(s1, s2) {
|
|
16489
16489
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
16490
16490
|
}
|
|
16491
|
-
function
|
|
16491
|
+
function resolve4(root, ref) {
|
|
16492
16492
|
let sch;
|
|
16493
16493
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
16494
16494
|
ref = sch;
|
|
@@ -17318,7 +17318,7 @@ var require_fast_uri = __commonJS({
|
|
|
17318
17318
|
}
|
|
17319
17319
|
return uri;
|
|
17320
17320
|
}
|
|
17321
|
-
function
|
|
17321
|
+
function resolve4(baseURI, relativeURI, options) {
|
|
17322
17322
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
17323
17323
|
const {
|
|
17324
17324
|
parsed: baseParsed,
|
|
@@ -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, relative4, options, skipNormalization) {
|
|
17355
17355
|
const target = {};
|
|
17356
17356
|
if (!skipNormalization) {
|
|
17357
17357
|
base = parse4(serialize(base, options), options);
|
|
17358
|
-
|
|
17358
|
+
relative4 = parse4(serialize(relative4, 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 && relative4.scheme) {
|
|
17362
|
+
target.scheme = relative4.scheme;
|
|
17363
|
+
target.userinfo = relative4.userinfo;
|
|
17364
|
+
target.host = relative4.host;
|
|
17365
|
+
target.port = relative4.port;
|
|
17366
|
+
target.path = removeDotSegments(relative4.path || "");
|
|
17367
|
+
target.query = relative4.query;
|
|
17368
17368
|
} else {
|
|
17369
|
-
if (
|
|
17370
|
-
target.userinfo =
|
|
17371
|
-
target.host =
|
|
17372
|
-
target.port =
|
|
17373
|
-
target.path = removeDotSegments(
|
|
17374
|
-
target.query =
|
|
17369
|
+
if (relative4.userinfo !== void 0 || relative4.host !== void 0 || relative4.port !== void 0) {
|
|
17370
|
+
target.userinfo = relative4.userinfo;
|
|
17371
|
+
target.host = relative4.host;
|
|
17372
|
+
target.port = relative4.port;
|
|
17373
|
+
target.path = removeDotSegments(relative4.path || "");
|
|
17374
|
+
target.query = relative4.query;
|
|
17375
17375
|
} else {
|
|
17376
|
-
if (!
|
|
17376
|
+
if (!relative4.path) {
|
|
17377
17377
|
target.path = base.path;
|
|
17378
|
-
if (
|
|
17379
|
-
target.query =
|
|
17378
|
+
if (relative4.query !== void 0) {
|
|
17379
|
+
target.query = relative4.query;
|
|
17380
17380
|
} else {
|
|
17381
17381
|
target.query = base.query;
|
|
17382
17382
|
}
|
|
17383
17383
|
} else {
|
|
17384
|
-
if (
|
|
17385
|
-
target.path = removeDotSegments(
|
|
17384
|
+
if (relative4.path[0] === "/") {
|
|
17385
|
+
target.path = removeDotSegments(relative4.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 = "/" + relative4.path;
|
|
17389
17389
|
} else if (!base.path) {
|
|
17390
|
-
target.path =
|
|
17390
|
+
target.path = relative4.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) + relative4.path;
|
|
17393
17393
|
}
|
|
17394
17394
|
target.path = removeDotSegments(target.path);
|
|
17395
17395
|
}
|
|
17396
|
-
target.query =
|
|
17396
|
+
target.query = relative4.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 = relative4.fragment;
|
|
17405
17405
|
return target;
|
|
17406
17406
|
}
|
|
17407
17407
|
function equal(uriA, uriB, options) {
|
|
@@ -17687,7 +17687,7 @@ var require_fast_uri = __commonJS({
|
|
|
17687
17687
|
var fastUri = {
|
|
17688
17688
|
SCHEMES,
|
|
17689
17689
|
normalize,
|
|
17690
|
-
resolve:
|
|
17690
|
+
resolve: resolve4,
|
|
17691
17691
|
resolveComponent,
|
|
17692
17692
|
equal,
|
|
17693
17693
|
serialize,
|
|
@@ -20678,10 +20678,10 @@ var require_dist2 = __commonJS({
|
|
|
20678
20678
|
|
|
20679
20679
|
// apps/zaku-cli/src/cli.ts
|
|
20680
20680
|
var import_reflect_metadata3 = __toESM(require_Reflect(), 1);
|
|
20681
|
-
import { readFile as
|
|
20681
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
20682
20682
|
import { createRequire } from "node:module";
|
|
20683
20683
|
import { homedir as homedir2 } from "node:os";
|
|
20684
|
-
import { dirname as
|
|
20684
|
+
import { dirname as dirname5, join as join13, relative as relative3, resolve as resolve3, 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
|
|
@@ -24111,7 +24111,7 @@ function bootstrap(scope, tokens) {
|
|
|
24111
24111
|
}
|
|
24112
24112
|
|
|
24113
24113
|
// apps/zaku-cli/src/dependencies.ts
|
|
24114
|
-
var
|
|
24114
|
+
var import_tsyringe11 = __toESM(require_cjs(), 1);
|
|
24115
24115
|
import { homedir } from "node:os";
|
|
24116
24116
|
|
|
24117
24117
|
// packages/zaku/dist/index.js
|
|
@@ -24154,11 +24154,13 @@ async function decodePreset(code, run) {
|
|
|
24154
24154
|
// packages/zaku/dist/lib/commands/write-tokens.js
|
|
24155
24155
|
var WriteTokens = class extends DomainCommand {
|
|
24156
24156
|
root;
|
|
24157
|
+
config;
|
|
24157
24158
|
cwd;
|
|
24158
24159
|
css;
|
|
24159
24160
|
constructor(input2) {
|
|
24160
24161
|
super();
|
|
24161
24162
|
this.root = input2.root;
|
|
24163
|
+
this.config = input2.config;
|
|
24162
24164
|
this.cwd = input2.cwd;
|
|
24163
24165
|
this.css = input2.css;
|
|
24164
24166
|
}
|
|
@@ -24167,10 +24169,12 @@ var WriteTokens = class extends DomainCommand {
|
|
|
24167
24169
|
// packages/zaku/dist/lib/commands/write-recipe.js
|
|
24168
24170
|
var WriteRecipe = class extends DomainCommand {
|
|
24169
24171
|
root;
|
|
24172
|
+
config;
|
|
24170
24173
|
url;
|
|
24171
24174
|
constructor(input2) {
|
|
24172
24175
|
super();
|
|
24173
24176
|
this.root = input2.root;
|
|
24177
|
+
this.config = input2.config;
|
|
24174
24178
|
this.url = input2.url;
|
|
24175
24179
|
}
|
|
24176
24180
|
};
|
|
@@ -24178,11 +24182,13 @@ var WriteRecipe = class extends DomainCommand {
|
|
|
24178
24182
|
// packages/zaku/dist/lib/commands/save-library.js
|
|
24179
24183
|
var SaveLibrary = class extends DomainCommand {
|
|
24180
24184
|
root;
|
|
24185
|
+
config;
|
|
24181
24186
|
key;
|
|
24182
24187
|
part;
|
|
24183
24188
|
constructor(input2) {
|
|
24184
24189
|
super();
|
|
24185
24190
|
this.root = input2.root;
|
|
24191
|
+
this.config = input2.config;
|
|
24186
24192
|
if (input2.key !== void 0)
|
|
24187
24193
|
this.key = input2.key;
|
|
24188
24194
|
if (input2.part !== void 0)
|
|
@@ -24193,10 +24199,12 @@ var SaveLibrary = class extends DomainCommand {
|
|
|
24193
24199
|
// packages/zaku/dist/lib/commands/write-outline.js
|
|
24194
24200
|
var WriteOutline = class extends DomainCommand {
|
|
24195
24201
|
root;
|
|
24202
|
+
config;
|
|
24196
24203
|
frames;
|
|
24197
24204
|
constructor(input2) {
|
|
24198
24205
|
super();
|
|
24199
24206
|
this.root = input2.root;
|
|
24207
|
+
this.config = input2.config;
|
|
24200
24208
|
this.frames = input2.frames;
|
|
24201
24209
|
}
|
|
24202
24210
|
};
|
|
@@ -24236,7 +24244,6 @@ var TOKENS = {
|
|
|
24236
24244
|
RUN_COMMAND: "zaku.runCommand",
|
|
24237
24245
|
RECIPE_PAGE_READER: "zaku.recipePageReader",
|
|
24238
24246
|
BUDGET_LEDGER: "zaku.budgetLedger",
|
|
24239
|
-
DESIGN_CONFIG_REPOSITORY: "zaku.designConfigRepository",
|
|
24240
24247
|
TOKEN_DOCUMENT_REPOSITORY: "zaku.tokenDocumentRepository",
|
|
24241
24248
|
RECIPE_REPOSITORY: "zaku.recipeRepository",
|
|
24242
24249
|
JSON_SCHEMA_FILES: "zaku.jsonSchemaFiles",
|
|
@@ -29385,7 +29392,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
29385
29392
|
var NONE = 0;
|
|
29386
29393
|
var ASSUMED = 1;
|
|
29387
29394
|
var PROVEN = 2;
|
|
29388
|
-
function isRecursive(inst, stack,
|
|
29395
|
+
function isRecursive(inst, stack, resolve4) {
|
|
29389
29396
|
const cached2 = recursive.get(inst);
|
|
29390
29397
|
if (cached2 !== void 0)
|
|
29391
29398
|
return cached2 ? PROVEN : NONE;
|
|
@@ -29395,7 +29402,7 @@ function isRecursive(inst, stack, resolve3) {
|
|
|
29395
29402
|
let result = NONE;
|
|
29396
29403
|
const check2 = (child) => {
|
|
29397
29404
|
if (result !== PROVEN && child?._zod) {
|
|
29398
|
-
const answer = isRecursive(child, stack,
|
|
29405
|
+
const answer = isRecursive(child, stack, resolve4);
|
|
29399
29406
|
if (answer > result)
|
|
29400
29407
|
result = answer;
|
|
29401
29408
|
}
|
|
@@ -29406,7 +29413,7 @@ function isRecursive(inst, stack, resolve3) {
|
|
|
29406
29413
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
29407
29414
|
if (spread && !desc.enumerable)
|
|
29408
29415
|
continue;
|
|
29409
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
29416
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve4) : NONE;
|
|
29410
29417
|
if (child > answer)
|
|
29411
29418
|
answer = child;
|
|
29412
29419
|
}
|
|
@@ -29470,7 +29477,7 @@ function isRecursive(inst, stack, resolve3) {
|
|
|
29470
29477
|
break;
|
|
29471
29478
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
29472
29479
|
case "lazy": {
|
|
29473
|
-
const inner = def._cachedInner ?? (
|
|
29480
|
+
const inner = def._cachedInner ?? (resolve4 ? inst._zod.innerType : void 0);
|
|
29474
29481
|
merge3(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
29475
29482
|
break;
|
|
29476
29483
|
}
|
|
@@ -44362,7 +44369,7 @@ function dtcgTokenDocument(system, schemes, name) {
|
|
|
44362
44369
|
// packages/zaku/dist/lib/domain/errors/css-required.js
|
|
44363
44370
|
var CssRequired = class extends Error {
|
|
44364
44371
|
constructor() {
|
|
44365
|
-
super("zaku tokens needs
|
|
44372
|
+
super("zaku tokens needs designSystem.shadcn.css, the stylesheet that declares :root and .dark, or --css when it runs on one product");
|
|
44366
44373
|
this.name = "CssRequired";
|
|
44367
44374
|
}
|
|
44368
44375
|
};
|
|
@@ -44417,6 +44424,34 @@ var PlaywrightMissing = class extends Error {
|
|
|
44417
44424
|
}
|
|
44418
44425
|
};
|
|
44419
44426
|
|
|
44427
|
+
// packages/zaku/dist/lib/domain/errors/product-config-missing.js
|
|
44428
|
+
var ProductConfigMissing = class extends Error {
|
|
44429
|
+
path;
|
|
44430
|
+
product;
|
|
44431
|
+
constructor(path2, product) {
|
|
44432
|
+
super(`no ${path2}, the zaku.yaml of the product ${product} the workspace config lists`);
|
|
44433
|
+
this.path = path2;
|
|
44434
|
+
this.product = product;
|
|
44435
|
+
this.name = "ProductConfigMissing";
|
|
44436
|
+
}
|
|
44437
|
+
};
|
|
44438
|
+
|
|
44439
|
+
// packages/zaku/dist/lib/domain/errors/product-required.js
|
|
44440
|
+
var ProductRequired = class extends Error {
|
|
44441
|
+
constructor(command, listed) {
|
|
44442
|
+
super(`${command} acts on one product; name one with --product: ${listed.join(", ")}`);
|
|
44443
|
+
this.name = "ProductRequired";
|
|
44444
|
+
}
|
|
44445
|
+
};
|
|
44446
|
+
|
|
44447
|
+
// packages/zaku/dist/lib/domain/errors/product-unknown.js
|
|
44448
|
+
var ProductUnknown = class extends Error {
|
|
44449
|
+
constructor(name, listed) {
|
|
44450
|
+
super(`no product ${name}; the config lists ${listed.join(", ")}`);
|
|
44451
|
+
this.name = "ProductUnknown";
|
|
44452
|
+
}
|
|
44453
|
+
};
|
|
44454
|
+
|
|
44420
44455
|
// packages/zaku/dist/lib/domain/errors/recipe-page-failed.js
|
|
44421
44456
|
var RecipePageFailed = class extends Error {
|
|
44422
44457
|
constructor(cause) {
|
|
@@ -44433,6 +44468,18 @@ var RecipeUrlRequired = class extends Error {
|
|
|
44433
44468
|
}
|
|
44434
44469
|
};
|
|
44435
44470
|
|
|
44471
|
+
// packages/zaku/dist/lib/domain/errors/workspace-config-missing.js
|
|
44472
|
+
var WorkspaceConfigMissing = class extends Error {
|
|
44473
|
+
path;
|
|
44474
|
+
legacy;
|
|
44475
|
+
constructor(path2, legacy) {
|
|
44476
|
+
super(legacy === null ? `no ${path2}` : `no ${path2}, and no ${legacy} to fall back on; run zaku where zaku.config.yaml is, or name it with --config`);
|
|
44477
|
+
this.path = path2;
|
|
44478
|
+
this.legacy = legacy;
|
|
44479
|
+
this.name = "WorkspaceConfigMissing";
|
|
44480
|
+
}
|
|
44481
|
+
};
|
|
44482
|
+
|
|
44436
44483
|
// packages/zaku/dist/lib/domain/theme-css.js
|
|
44437
44484
|
function declarations(css, selector) {
|
|
44438
44485
|
const escaped = selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -44452,19 +44499,17 @@ function parseThemeCss(css) {
|
|
|
44452
44499
|
|
|
44453
44500
|
// packages/zaku/dist/lib/handlers/write-tokens.js
|
|
44454
44501
|
var WriteTokensHandler = class WriteTokensHandler2 {
|
|
44455
|
-
configs;
|
|
44456
44502
|
documents;
|
|
44457
44503
|
files;
|
|
44458
44504
|
run;
|
|
44459
44505
|
command = WriteTokens;
|
|
44460
|
-
constructor(
|
|
44461
|
-
this.configs = configs;
|
|
44506
|
+
constructor(documents, files2, run) {
|
|
44462
44507
|
this.documents = documents;
|
|
44463
44508
|
this.files = files2;
|
|
44464
44509
|
this.run = run;
|
|
44465
44510
|
}
|
|
44466
44511
|
async handle(command) {
|
|
44467
|
-
const config2 =
|
|
44512
|
+
const { config: config2 } = command;
|
|
44468
44513
|
const system = config2.designSystem;
|
|
44469
44514
|
let doc;
|
|
44470
44515
|
let from;
|
|
@@ -44489,10 +44534,9 @@ var WriteTokensHandler = class WriteTokensHandler2 {
|
|
|
44489
44534
|
};
|
|
44490
44535
|
WriteTokensHandler = __decorate2([
|
|
44491
44536
|
(0, import_tsyringe.injectable)({ token: TOKENS.COMMAND_HANDLER }),
|
|
44492
|
-
__param2(0, (0, import_tsyringe.inject)(TOKENS.
|
|
44493
|
-
__param2(1, (0, import_tsyringe.inject)(TOKENS.
|
|
44494
|
-
__param2(2, (0, import_tsyringe.inject)(TOKENS.
|
|
44495
|
-
__param2(3, (0, import_tsyringe.inject)(TOKENS.RUN_COMMAND))
|
|
44537
|
+
__param2(0, (0, import_tsyringe.inject)(TOKENS.TOKEN_DOCUMENT_REPOSITORY)),
|
|
44538
|
+
__param2(1, (0, import_tsyringe.inject)(TOKENS.SOURCE_FILES)),
|
|
44539
|
+
__param2(2, (0, import_tsyringe.inject)(TOKENS.RUN_COMMAND))
|
|
44496
44540
|
], WriteTokensHandler);
|
|
44497
44541
|
|
|
44498
44542
|
// packages/zaku/dist/lib/handlers/write-recipe.js
|
|
@@ -44587,17 +44631,15 @@ ${JSON.stringify(Object.entries(props).sort(([a], [b]) => a.localeCompare(b)))}`
|
|
|
44587
44631
|
|
|
44588
44632
|
// packages/zaku/dist/lib/handlers/write-recipe.js
|
|
44589
44633
|
var WriteRecipeHandler = class WriteRecipeHandler2 {
|
|
44590
|
-
configs;
|
|
44591
44634
|
recipes;
|
|
44592
44635
|
readPage;
|
|
44593
44636
|
command = WriteRecipe;
|
|
44594
|
-
constructor(
|
|
44595
|
-
this.configs = configs;
|
|
44637
|
+
constructor(recipes, readPage) {
|
|
44596
44638
|
this.recipes = recipes;
|
|
44597
44639
|
this.readPage = readPage;
|
|
44598
44640
|
}
|
|
44599
44641
|
async handle(command) {
|
|
44600
|
-
const config2 =
|
|
44642
|
+
const { config: config2 } = command;
|
|
44601
44643
|
const url2 = command.url ?? config2.recipe?.url;
|
|
44602
44644
|
if (!url2)
|
|
44603
44645
|
throw new RecipeUrlRequired();
|
|
@@ -44620,17 +44662,41 @@ var WriteRecipeHandler = class WriteRecipeHandler2 {
|
|
|
44620
44662
|
};
|
|
44621
44663
|
WriteRecipeHandler = __decorate2([
|
|
44622
44664
|
(0, import_tsyringe2.injectable)({ token: TOKENS.COMMAND_HANDLER }),
|
|
44623
|
-
__param2(0, (0, import_tsyringe2.inject)(TOKENS.
|
|
44624
|
-
__param2(1, (0, import_tsyringe2.inject)(TOKENS.
|
|
44625
|
-
__param2(2, (0, import_tsyringe2.inject)(TOKENS.RECIPE_PAGE_READER))
|
|
44665
|
+
__param2(0, (0, import_tsyringe2.inject)(TOKENS.RECIPE_REPOSITORY)),
|
|
44666
|
+
__param2(1, (0, import_tsyringe2.inject)(TOKENS.RECIPE_PAGE_READER))
|
|
44626
44667
|
], WriteRecipeHandler);
|
|
44627
44668
|
|
|
44628
44669
|
// packages/zaku/dist/lib/handlers/save-library.js
|
|
44629
44670
|
var import_tsyringe3 = __toESM(require_cjs(), 1);
|
|
44630
44671
|
import { relative as relative2 } from "node:path";
|
|
44631
44672
|
|
|
44632
|
-
// packages/zaku/dist/lib/
|
|
44633
|
-
|
|
44673
|
+
// packages/zaku/dist/lib/repositories/design-paths.js
|
|
44674
|
+
import { join as join2 } from "node:path";
|
|
44675
|
+
function librarySnapshotDir(paths, key) {
|
|
44676
|
+
if (key === null)
|
|
44677
|
+
return paths;
|
|
44678
|
+
const library = join2(paths.library, key);
|
|
44679
|
+
return { root: paths.root, library, libraryIndex: join2(library, "index.json"), legacyLibrary: null };
|
|
44680
|
+
}
|
|
44681
|
+
function designPaths(root) {
|
|
44682
|
+
return {
|
|
44683
|
+
root,
|
|
44684
|
+
config: join2(root, "zaku.yaml"),
|
|
44685
|
+
maps: join2(root, "map"),
|
|
44686
|
+
outline: join2(root, "outline"),
|
|
44687
|
+
unmapped: join2(root, "outline", "unmapped.yaml"),
|
|
44688
|
+
files: join2(root, "outline", "files.yaml"),
|
|
44689
|
+
library: join2(root, "library"),
|
|
44690
|
+
libraryIndex: join2(root, "library", "index.json"),
|
|
44691
|
+
legacyLibrary: join2(root, "library.json"),
|
|
44692
|
+
tokens: join2(root, "tokens.json"),
|
|
44693
|
+
recipe: join2(root, "recipe.json")
|
|
44694
|
+
};
|
|
44695
|
+
}
|
|
44696
|
+
|
|
44697
|
+
// packages/zaku/dist/lib/repositories/library-snapshot.js
|
|
44698
|
+
import { mkdir, readdir, readFile as readFile2, rename as rename2, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
44699
|
+
import { join as join3, relative } from "node:path";
|
|
44634
44700
|
|
|
44635
44701
|
// packages/zaku/dist/lib/domain/design-graph.js
|
|
44636
44702
|
var DESKTOP_FAMILIES = /* @__PURE__ */ new Set(["macos", "windows", "gnome", "kde"]);
|
|
@@ -44639,21 +44705,15 @@ function defaultBranch(family) {
|
|
|
44639
44705
|
return "ui";
|
|
44640
44706
|
return DESKTOP_FAMILIES.has(family) ? void 0 : "native";
|
|
44641
44707
|
}
|
|
44642
|
-
function defaultPlatform(family) {
|
|
44643
|
-
if (family === "web")
|
|
44644
|
-
return "web-app";
|
|
44645
|
-
return DESKTOP_FAMILIES.has(family) ? "desktop" : "mobile";
|
|
44646
|
-
}
|
|
44647
44708
|
var branchOf = (target) => target.branch ?? defaultBranch(target.family);
|
|
44648
|
-
var platformOf = (target) => target.platform ?? defaultPlatform(target.family);
|
|
44649
44709
|
var unique = (values) => [...new Set(values)];
|
|
44650
44710
|
function legacyFiles(config2) {
|
|
44651
44711
|
const branches = unique(config2.targets.flatMap((target) => branchOf(target) ?? []));
|
|
44652
|
-
const
|
|
44712
|
+
const families2 = unique(config2.targets.map((target) => target.family));
|
|
44653
44713
|
const { library, product } = config2.figma;
|
|
44654
44714
|
return {
|
|
44655
44715
|
libraries: library === void 0 ? [] : [{ key: library, layer: "foundations", branches: branches.length > 0 ? branches : ["ui"], extends: [] }],
|
|
44656
|
-
products: product === void 0 ? [] :
|
|
44716
|
+
products: product === void 0 ? [] : families2.map((family) => ({ key: product, family }))
|
|
44657
44717
|
};
|
|
44658
44718
|
}
|
|
44659
44719
|
function designGraph(config2) {
|
|
@@ -44682,7 +44742,7 @@ function designGraph(config2) {
|
|
|
44682
44742
|
prototypes,
|
|
44683
44743
|
legacy,
|
|
44684
44744
|
branchOf,
|
|
44685
|
-
|
|
44745
|
+
targetsOf: (family) => config2.targets.filter((target) => target.family === family),
|
|
44686
44746
|
librariesFor: (target) => {
|
|
44687
44747
|
if (legacy)
|
|
44688
44748
|
return libraries;
|
|
@@ -44694,7 +44754,7 @@ function designGraph(config2) {
|
|
|
44694
44754
|
multiBranch: (key) => (byKey.get(key)?.branches.length ?? 0) > 1,
|
|
44695
44755
|
productOf: (prototypeKey) => {
|
|
44696
44756
|
const prototype2 = prototypes.find((candidate) => candidate.key === prototypeKey);
|
|
44697
|
-
return
|
|
44757
|
+
return products.find((product) => product.family === prototype2?.family)?.key;
|
|
44698
44758
|
}
|
|
44699
44759
|
};
|
|
44700
44760
|
}
|
|
@@ -44722,337 +44782,6 @@ function snapshotsFor(input2, target) {
|
|
|
44722
44782
|
return { libraries, kits, missing };
|
|
44723
44783
|
}
|
|
44724
44784
|
|
|
44725
|
-
// packages/zaku/dist/lib/schema/zaku-config.js
|
|
44726
|
-
var PLATFORM_FAMILIES = ["web", "ios", "android", "macos", "windows", "gnome", "kde"];
|
|
44727
|
-
var LAYERS = ["foundations", "components"];
|
|
44728
|
-
var BRANCHES = ["ui", "native"];
|
|
44729
|
-
var PLATFORMS = ["web-app", "mobile", "desktop"];
|
|
44730
|
-
var DEFAULT_INTERACTIVE = [
|
|
44731
|
-
"Button",
|
|
44732
|
-
"Button Group",
|
|
44733
|
-
"Checkbox",
|
|
44734
|
-
"Combobox",
|
|
44735
|
-
"Dropdown Menu",
|
|
44736
|
-
"Input",
|
|
44737
|
-
"Input Group",
|
|
44738
|
-
"Input OTP",
|
|
44739
|
-
"Native Select",
|
|
44740
|
-
"Pagination",
|
|
44741
|
-
"Radio Group",
|
|
44742
|
-
"Select",
|
|
44743
|
-
"Slider",
|
|
44744
|
-
"Switch",
|
|
44745
|
-
"Tabs",
|
|
44746
|
-
"Textarea",
|
|
44747
|
-
"Toggle",
|
|
44748
|
-
"Toggle Group"
|
|
44749
|
-
];
|
|
44750
|
-
var id = external_exports.string().regex(/^[a-z][a-z0-9-]*$/, "lowercase letters, digits and dashes, starting with a letter");
|
|
44751
|
-
var targetSchema = external_exports.object({
|
|
44752
|
-
id,
|
|
44753
|
-
family: external_exports.enum(PLATFORM_FAMILIES),
|
|
44754
|
-
name: external_exports.string().regex(/^\S(.*\S)?$/, "a name has no leading or trailing space").refine((name) => !name.includes("/"), "a name has no slash, which separates the parts of a frame name"),
|
|
44755
|
-
/** The frame size every frame of this target is drawn at; the frame check compares it. */
|
|
44756
|
-
size: external_exports.object({ width: external_exports.number().positive(), height: external_exports.number().positive() }).strict().optional(),
|
|
44757
|
-
/** The renderer whose libraries its frames draw from; `defaultBranch` in the design graph gives it when left out. */
|
|
44758
|
-
branch: external_exports.enum(BRANCHES).optional(),
|
|
44759
|
-
/** What its frames serve; `defaultPlatform` in the design graph gives it when left out. */
|
|
44760
|
-
platform: external_exports.enum(PLATFORMS).optional()
|
|
44761
|
-
}).strict();
|
|
44762
|
-
var DEFAULT_SYSTEM_BARS = {
|
|
44763
|
-
web: [],
|
|
44764
|
-
ios: [["Status Bar"], ["Home Indicator"]],
|
|
44765
|
-
android: [["Status Bar"], ["Navigation Bar", "Gesture Handle"]],
|
|
44766
|
-
macos: [["Window Controls"]],
|
|
44767
|
-
windows: [["Title Bar"]],
|
|
44768
|
-
gnome: [["Header Bar"]],
|
|
44769
|
-
kde: [["Title Bar"]]
|
|
44770
|
-
};
|
|
44771
|
-
function systemBarNames(config2) {
|
|
44772
|
-
const bars = { ...DEFAULT_SYSTEM_BARS, ...config2.systemBars };
|
|
44773
|
-
return new Set(Object.values(bars).flat(2));
|
|
44774
|
-
}
|
|
44775
|
-
var budgetSchema = external_exports.object({
|
|
44776
|
-
mcpPerDay: external_exports.number().int().positive().default(200),
|
|
44777
|
-
mcpPerRun: external_exports.number().int().positive().default(30),
|
|
44778
|
-
reserve: external_exports.number().min(0).max(1).default(0.2)
|
|
44779
|
-
}).strict();
|
|
44780
|
-
var fileKey = external_exports.string().min(1);
|
|
44781
|
-
var kitSchema = external_exports.object({ key: fileKey, family: external_exports.enum(PLATFORM_FAMILIES) }).strict();
|
|
44782
|
-
var librarySchema = external_exports.object({
|
|
44783
|
-
key: fileKey,
|
|
44784
|
-
layer: external_exports.enum(LAYERS),
|
|
44785
|
-
branches: external_exports.array(external_exports.enum(BRANCHES)).min(1),
|
|
44786
|
-
/** The libraries and kits this one is built on, by key. */
|
|
44787
|
-
extends: external_exports.array(fileKey).default([])
|
|
44788
|
-
}).strict();
|
|
44789
|
-
var productSchema = external_exports.object({ key: fileKey, platform: external_exports.enum(PLATFORMS) }).strict();
|
|
44790
|
-
var prototypeSchema = external_exports.object({
|
|
44791
|
-
key: fileKey,
|
|
44792
|
-
platform: external_exports.enum(PLATFORMS),
|
|
44793
|
-
/** The product file its frames are copied from; required when there are several. */
|
|
44794
|
-
product: fileKey.optional()
|
|
44795
|
-
}).strict();
|
|
44796
|
-
var files = external_exports.object({
|
|
44797
|
-
library: fileKey.optional(),
|
|
44798
|
-
product: fileKey.optional(),
|
|
44799
|
-
kits: external_exports.array(kitSchema).optional(),
|
|
44800
|
-
libraries: external_exports.array(librarySchema).optional(),
|
|
44801
|
-
products: external_exports.array(productSchema).optional(),
|
|
44802
|
-
prototypes: external_exports.array(prototypeSchema).optional()
|
|
44803
|
-
}).strict();
|
|
44804
|
-
function byRole(figma) {
|
|
44805
|
-
return [figma.kits, figma.libraries, figma.products, figma.prototypes].some((list) => list !== void 0);
|
|
44806
|
-
}
|
|
44807
|
-
var shadcnSystem = external_exports.object({ preset: external_exports.string().min(1) }).strict();
|
|
44808
|
-
var tokenFiles = external_exports.array(external_exports.string().min(1)).min(1);
|
|
44809
|
-
var resolverInputs = external_exports.record(external_exports.string(), external_exports.string());
|
|
44810
|
-
var dtcgSystem = external_exports.object({
|
|
44811
|
-
resolver: external_exports.string().min(1).optional(),
|
|
44812
|
-
light: external_exports.union([tokenFiles, resolverInputs]),
|
|
44813
|
-
dark: external_exports.union([tokenFiles, resolverInputs]),
|
|
44814
|
-
/** The group whose tokens are the colour roles, and the one whose tokens are the radius steps. */
|
|
44815
|
-
colors: external_exports.string().min(1).default("color"),
|
|
44816
|
-
radii: external_exports.string().min(1).default("radius"),
|
|
44817
|
-
/** Foreground and background token pairs a text is read in, each needing 4.5:1. */
|
|
44818
|
-
contrast: external_exports.array(external_exports.tuple([external_exports.string().min(1), external_exports.string().min(1)])).default([])
|
|
44819
|
-
}).strict().superRefine((dtcg, ctx) => {
|
|
44820
|
-
for (const scheme of ["light", "dark"]) {
|
|
44821
|
-
const files2 = Array.isArray(dtcg[scheme]);
|
|
44822
|
-
if (dtcg.resolver !== void 0 && files2) {
|
|
44823
|
-
ctx.addIssue({
|
|
44824
|
-
code: "custom",
|
|
44825
|
-
path: [scheme],
|
|
44826
|
-
message: "with a resolver, name the modifier contexts, not files"
|
|
44827
|
-
});
|
|
44828
|
-
}
|
|
44829
|
-
if (dtcg.resolver === void 0 && !files2) {
|
|
44830
|
-
ctx.addIssue({
|
|
44831
|
-
code: "custom",
|
|
44832
|
-
path: [scheme],
|
|
44833
|
-
message: "without a resolver, list the token files"
|
|
44834
|
-
});
|
|
44835
|
-
}
|
|
44836
|
-
}
|
|
44837
|
-
});
|
|
44838
|
-
var designSystemSchema = external_exports.union([
|
|
44839
|
-
external_exports.object({ shadcn: shadcnSystem }).strict(),
|
|
44840
|
-
external_exports.object({ dtcg: dtcgSystem }).strict()
|
|
44841
|
-
]);
|
|
44842
|
-
var recipeSchema = external_exports.object({
|
|
44843
|
-
url: external_exports.url().optional(),
|
|
44844
|
-
dark: external_exports.enum(["class", "media"]).default("class"),
|
|
44845
|
-
darkClass: external_exports.string().min(1).default("dark")
|
|
44846
|
-
}).strict();
|
|
44847
|
-
function writtenInAScript(tag) {
|
|
44848
|
-
try {
|
|
44849
|
-
return new Intl.Locale(tag).maximize().script !== void 0;
|
|
44850
|
-
} catch {
|
|
44851
|
-
return false;
|
|
44852
|
-
}
|
|
44853
|
-
}
|
|
44854
|
-
var copySchema = external_exports.object({
|
|
44855
|
-
locales: external_exports.array(external_exports.string().refine(writtenInAScript, "a BCP 47 language tag, such as en or vi")).min(1).default(["en"]),
|
|
44856
|
-
currencies: external_exports.array(external_exports.string().refine((code) => Intl.supportedValuesOf("currency").includes(code), "an ISO 4217 code, such as VND or USD")).default([])
|
|
44857
|
-
}).strict();
|
|
44858
|
-
var configShape = external_exports.object({
|
|
44859
|
-
product: external_exports.string().min(1),
|
|
44860
|
-
designSystem: designSystemSchema,
|
|
44861
|
-
figma: files.default({}),
|
|
44862
|
-
targets: external_exports.array(targetSchema).min(1),
|
|
44863
|
-
modes: external_exports.record(external_exports.string(), external_exports.string()).default({}),
|
|
44864
|
-
interactive: external_exports.array(external_exports.string().min(1)).default([...DEFAULT_INTERACTIVE]),
|
|
44865
|
-
/** The bars of the families whose kit names them its own way; every family left out keeps its default. */
|
|
44866
|
-
systemBars: external_exports.partialRecord(external_exports.enum(PLATFORM_FAMILIES), external_exports.array(external_exports.array(external_exports.string().min(1)).min(1))).optional(),
|
|
44867
|
-
budget: budgetSchema.default({ mcpPerDay: 200, mcpPerRun: 30, reserve: 0.2 }),
|
|
44868
|
-
recipe: recipeSchema.optional(),
|
|
44869
|
-
copy: copySchema.default(DEFAULT_COPY)
|
|
44870
|
-
}).strict();
|
|
44871
|
-
var zakuConfigSchema = configShape.superRefine((config2, ctx) => {
|
|
44872
|
-
for (const key of ["id", "name"]) {
|
|
44873
|
-
const seen = /* @__PURE__ */ new Set();
|
|
44874
|
-
config2.targets.forEach((target, index) => {
|
|
44875
|
-
if (seen.has(target[key])) {
|
|
44876
|
-
ctx.addIssue({
|
|
44877
|
-
code: "custom",
|
|
44878
|
-
path: ["targets", index, key],
|
|
44879
|
-
message: `a second target with ${key} ${target[key]}`
|
|
44880
|
-
});
|
|
44881
|
-
}
|
|
44882
|
-
seen.add(target[key]);
|
|
44883
|
-
});
|
|
44884
|
-
}
|
|
44885
|
-
if (byRole(config2.figma))
|
|
44886
|
-
refineFilesByRole(config2, ctx);
|
|
44887
|
-
});
|
|
44888
|
-
function refineFilesByRole(config2, ctx) {
|
|
44889
|
-
const { figma } = config2;
|
|
44890
|
-
if (figma.library !== void 0 || figma.product !== void 0) {
|
|
44891
|
-
ctx.addIssue({
|
|
44892
|
-
code: "custom",
|
|
44893
|
-
path: ["figma"],
|
|
44894
|
-
message: "figma.library and figma.product describe one library and one product; list files by role instead"
|
|
44895
|
-
});
|
|
44896
|
-
}
|
|
44897
|
-
const kits = figma.kits ?? [];
|
|
44898
|
-
const libraries = figma.libraries ?? [];
|
|
44899
|
-
const products = figma.products ?? [];
|
|
44900
|
-
const seen = /* @__PURE__ */ new Set();
|
|
44901
|
-
const lists = [
|
|
44902
|
-
["kits", kits],
|
|
44903
|
-
["libraries", libraries],
|
|
44904
|
-
["products", products],
|
|
44905
|
-
["prototypes", figma.prototypes ?? []]
|
|
44906
|
-
];
|
|
44907
|
-
for (const [list, entries] of lists) {
|
|
44908
|
-
entries.forEach((entry, index) => {
|
|
44909
|
-
if (seen.has(entry.key))
|
|
44910
|
-
ctx.addIssue({
|
|
44911
|
-
code: "custom",
|
|
44912
|
-
path: ["figma", list, index, "key"],
|
|
44913
|
-
message: `a second file with key ${entry.key}`
|
|
44914
|
-
});
|
|
44915
|
-
seen.add(entry.key);
|
|
44916
|
-
});
|
|
44917
|
-
}
|
|
44918
|
-
const byKey = new Map(libraries.map((library) => [library.key, library]));
|
|
44919
|
-
const kitKeys = new Set(kits.map((kit) => kit.key));
|
|
44920
|
-
libraries.forEach((library, index) => {
|
|
44921
|
-
const path2 = ["figma", "libraries", index, "extends"];
|
|
44922
|
-
for (const key of library.extends) {
|
|
44923
|
-
const base = byKey.get(key);
|
|
44924
|
-
if (!base && !kitKeys.has(key)) {
|
|
44925
|
-
ctx.addIssue({
|
|
44926
|
-
code: "custom",
|
|
44927
|
-
path: path2,
|
|
44928
|
-
message: `${library.key} extends ${key}, which is no library or kit listed`
|
|
44929
|
-
});
|
|
44930
|
-
} else if (base?.layer === "components" && library.layer === "foundations") {
|
|
44931
|
-
ctx.addIssue({ code: "custom", path: path2, message: `foundations ${library.key} extends components ${key}` });
|
|
44932
|
-
} else if (base && !base.branches.some((branch) => library.branches.includes(branch))) {
|
|
44933
|
-
ctx.addIssue({
|
|
44934
|
-
code: "custom",
|
|
44935
|
-
path: path2,
|
|
44936
|
-
message: `${library.key} extends ${key}, which holds none of its branches`
|
|
44937
|
-
});
|
|
44938
|
-
}
|
|
44939
|
-
}
|
|
44940
|
-
});
|
|
44941
|
-
const cycle = findCycle(libraries);
|
|
44942
|
-
if (cycle)
|
|
44943
|
-
ctx.addIssue({ code: "custom", path: ["figma", "libraries"], message: `extends comes back: ${cycle}` });
|
|
44944
|
-
(figma.prototypes ?? []).forEach((prototype2, index) => {
|
|
44945
|
-
const path2 = ["figma", "prototypes", index];
|
|
44946
|
-
if (prototype2.product === void 0) {
|
|
44947
|
-
if (products.length > 1)
|
|
44948
|
-
ctx.addIssue({ code: "custom", path: [...path2, "product"], message: "name the product its frames come from" });
|
|
44949
|
-
return;
|
|
44950
|
-
}
|
|
44951
|
-
const product = products.find((candidate) => candidate.key === prototype2.product);
|
|
44952
|
-
if (!product) {
|
|
44953
|
-
ctx.addIssue({ code: "custom", path: [...path2, "product"], message: `no product with key ${prototype2.product}` });
|
|
44954
|
-
} else if (product.platform !== prototype2.platform) {
|
|
44955
|
-
ctx.addIssue({
|
|
44956
|
-
code: "custom",
|
|
44957
|
-
path: [...path2, "platform"],
|
|
44958
|
-
message: `${prototype2.platform}, and its product serves ${product.platform}`
|
|
44959
|
-
});
|
|
44960
|
-
}
|
|
44961
|
-
});
|
|
44962
|
-
config2.targets.forEach((target, index) => {
|
|
44963
|
-
const branch = target.branch ?? defaultBranch(target.family);
|
|
44964
|
-
const path2 = ["targets", index, "branch"];
|
|
44965
|
-
if (branch === void 0) {
|
|
44966
|
-
ctx.addIssue({ code: "custom", path: path2, message: `a ${target.family} target names its branch, ui or native` });
|
|
44967
|
-
} else if (libraries.length > 0 && !libraries.some((library) => library.branches.includes(branch))) {
|
|
44968
|
-
ctx.addIssue({ code: "custom", path: path2, message: `no library holds the ${branch} branch` });
|
|
44969
|
-
}
|
|
44970
|
-
});
|
|
44971
|
-
}
|
|
44972
|
-
function findCycle(libraries) {
|
|
44973
|
-
const byKey = new Map(libraries.map((library) => [library.key, library]));
|
|
44974
|
-
const visit2 = (key, path2) => {
|
|
44975
|
-
if (path2.includes(key))
|
|
44976
|
-
return [...path2.slice(path2.indexOf(key)), key].join(" -> ");
|
|
44977
|
-
for (const next of byKey.get(key)?.extends ?? []) {
|
|
44978
|
-
const found = visit2(next, [...path2, key]);
|
|
44979
|
-
if (found)
|
|
44980
|
-
return found;
|
|
44981
|
-
}
|
|
44982
|
-
return void 0;
|
|
44983
|
-
};
|
|
44984
|
-
for (const library of libraries) {
|
|
44985
|
-
const found = visit2(library.key, []);
|
|
44986
|
-
if (found)
|
|
44987
|
-
return found;
|
|
44988
|
-
}
|
|
44989
|
-
return void 0;
|
|
44990
|
-
}
|
|
44991
|
-
|
|
44992
|
-
// packages/zaku/dist/lib/repositories/design-file.js
|
|
44993
|
-
var import_yaml = __toESM(require_dist(), 1);
|
|
44994
|
-
import { readFile, rename, writeFile } from "node:fs/promises";
|
|
44995
|
-
function parseDesignFile(path2, text, schema) {
|
|
44996
|
-
let data;
|
|
44997
|
-
try {
|
|
44998
|
-
data = path2.endsWith(".json") ? JSON.parse(text) : (0, import_yaml.parse)(text);
|
|
44999
|
-
} catch (error62) {
|
|
45000
|
-
throw new DesignFileInvalid(path2, [error62.message]);
|
|
45001
|
-
}
|
|
45002
|
-
const result = schema.safeParse(data);
|
|
45003
|
-
if (!result.success) {
|
|
45004
|
-
throw new DesignFileInvalid(path2, result.error.issues.map((issue2) => `${issue2.path.map(String).join(".") || "(root)"}: ${issue2.message}`));
|
|
45005
|
-
}
|
|
45006
|
-
return result.data;
|
|
45007
|
-
}
|
|
45008
|
-
async function readDesignFile(path2, schema) {
|
|
45009
|
-
return parseDesignFile(path2, await readFile(path2, "utf8"), schema);
|
|
45010
|
-
}
|
|
45011
|
-
async function readOptionalDesignFile(path2, schema) {
|
|
45012
|
-
let text;
|
|
45013
|
-
try {
|
|
45014
|
-
text = await readFile(path2, "utf8");
|
|
45015
|
-
} catch (error62) {
|
|
45016
|
-
if (error62.code === "ENOENT")
|
|
45017
|
-
return null;
|
|
45018
|
-
throw error62;
|
|
45019
|
-
}
|
|
45020
|
-
return parseDesignFile(path2, text, schema);
|
|
45021
|
-
}
|
|
45022
|
-
async function writeDesignFile(path2, value) {
|
|
45023
|
-
const temporary = `${path2}.${process.pid}.tmp`;
|
|
45024
|
-
await writeFile(temporary, `${JSON.stringify(value, null, 2)}
|
|
45025
|
-
`);
|
|
45026
|
-
await rename(temporary, path2);
|
|
45027
|
-
}
|
|
45028
|
-
|
|
45029
|
-
// packages/zaku/dist/lib/repositories/design-paths.js
|
|
45030
|
-
import { join as join2 } from "node:path";
|
|
45031
|
-
function librarySnapshotDir(paths, key) {
|
|
45032
|
-
if (key === null)
|
|
45033
|
-
return paths;
|
|
45034
|
-
const library = join2(paths.library, key);
|
|
45035
|
-
return { root: paths.root, library, libraryIndex: join2(library, "index.json"), legacyLibrary: null };
|
|
45036
|
-
}
|
|
45037
|
-
function designPaths(root) {
|
|
45038
|
-
return {
|
|
45039
|
-
root,
|
|
45040
|
-
config: join2(root, "zaku.yaml"),
|
|
45041
|
-
maps: join2(root, "map"),
|
|
45042
|
-
outline: join2(root, "outline"),
|
|
45043
|
-
unmapped: join2(root, "outline", "unmapped.yaml"),
|
|
45044
|
-
library: join2(root, "library"),
|
|
45045
|
-
libraryIndex: join2(root, "library", "index.json"),
|
|
45046
|
-
legacyLibrary: join2(root, "library.json"),
|
|
45047
|
-
tokens: join2(root, "tokens.json"),
|
|
45048
|
-
recipe: join2(root, "recipe.json")
|
|
45049
|
-
};
|
|
45050
|
-
}
|
|
45051
|
-
|
|
45052
|
-
// packages/zaku/dist/lib/repositories/library-snapshot.js
|
|
45053
|
-
import { mkdir, readdir, readFile as readFile2, rename as rename2, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
45054
|
-
import { join as join3, relative } from "node:path";
|
|
45055
|
-
|
|
45056
44785
|
// packages/zaku/dist/lib/domain/library.js
|
|
45057
44786
|
var rgbaSchema = external_exports.object({ r: external_exports.number(), g: external_exports.number(), b: external_exports.number(), a: external_exports.number() }).strict();
|
|
45058
44787
|
var libraryItemSchema = external_exports.object({
|
|
@@ -45341,6 +45070,43 @@ function formatLibraryFile(value) {
|
|
|
45341
45070
|
`;
|
|
45342
45071
|
}
|
|
45343
45072
|
|
|
45073
|
+
// packages/zaku/dist/lib/repositories/design-file.js
|
|
45074
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
45075
|
+
import { readFile, rename, writeFile } from "node:fs/promises";
|
|
45076
|
+
function parseDesignFile(path2, text, schema) {
|
|
45077
|
+
let data;
|
|
45078
|
+
try {
|
|
45079
|
+
data = path2.endsWith(".json") ? JSON.parse(text) : (0, import_yaml.parse)(text);
|
|
45080
|
+
} catch (error62) {
|
|
45081
|
+
throw new DesignFileInvalid(path2, [error62.message]);
|
|
45082
|
+
}
|
|
45083
|
+
const result = schema.safeParse(data);
|
|
45084
|
+
if (!result.success) {
|
|
45085
|
+
throw new DesignFileInvalid(path2, result.error.issues.map((issue2) => `${issue2.path.map(String).join(".") || "(root)"}: ${issue2.message}`));
|
|
45086
|
+
}
|
|
45087
|
+
return result.data;
|
|
45088
|
+
}
|
|
45089
|
+
async function readDesignFile(path2, schema) {
|
|
45090
|
+
return parseDesignFile(path2, await readFile(path2, "utf8"), schema);
|
|
45091
|
+
}
|
|
45092
|
+
async function readOptionalDesignFile(path2, schema) {
|
|
45093
|
+
let text;
|
|
45094
|
+
try {
|
|
45095
|
+
text = await readFile(path2, "utf8");
|
|
45096
|
+
} catch (error62) {
|
|
45097
|
+
if (error62.code === "ENOENT")
|
|
45098
|
+
return null;
|
|
45099
|
+
throw error62;
|
|
45100
|
+
}
|
|
45101
|
+
return parseDesignFile(path2, text, schema);
|
|
45102
|
+
}
|
|
45103
|
+
async function writeDesignFile(path2, value) {
|
|
45104
|
+
const temporary = `${path2}.${process.pid}.tmp`;
|
|
45105
|
+
await writeFile(temporary, `${JSON.stringify(value, null, 2)}
|
|
45106
|
+
`);
|
|
45107
|
+
await rename(temporary, path2);
|
|
45108
|
+
}
|
|
45109
|
+
|
|
45344
45110
|
// packages/zaku/dist/lib/repositories/library-snapshot.js
|
|
45345
45111
|
async function readText(path2) {
|
|
45346
45112
|
try {
|
|
@@ -45733,8 +45499,7 @@ function librarySaveTarget(config2, key) {
|
|
|
45733
45499
|
}
|
|
45734
45500
|
async function saveLibrary(options) {
|
|
45735
45501
|
const paths = designPaths(options.root);
|
|
45736
|
-
const
|
|
45737
|
-
const target = librarySaveTarget(config2, options.key);
|
|
45502
|
+
const target = librarySaveTarget(options.config, options.key);
|
|
45738
45503
|
if (target.kind === "kit") {
|
|
45739
45504
|
const at2 = librarySnapshotDir(paths, target.kit.key);
|
|
45740
45505
|
const kit = await readKit({ rest: options.rest, key: target.kit.key, family: target.kit.family });
|
|
@@ -45762,6 +45527,7 @@ var SaveLibraryHandler = class SaveLibraryHandler2 {
|
|
|
45762
45527
|
handle(command) {
|
|
45763
45528
|
return saveLibrary({
|
|
45764
45529
|
root: command.root,
|
|
45530
|
+
config: command.config,
|
|
45765
45531
|
rest: this.rest,
|
|
45766
45532
|
...command.key !== void 0 ? { key: command.key } : {},
|
|
45767
45533
|
...command.part !== void 0 ? { part: command.part } : {}
|
|
@@ -45780,6 +45546,85 @@ var import_yaml2 = __toESM(require_dist(), 1);
|
|
|
45780
45546
|
import { mkdir as mkdir2, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
|
|
45781
45547
|
import { dirname as dirname2, join as join6 } from "node:path";
|
|
45782
45548
|
|
|
45549
|
+
// packages/zaku/dist/lib/adapters/figma-rest.js
|
|
45550
|
+
var FigmaRateLimited = class extends Error {
|
|
45551
|
+
url;
|
|
45552
|
+
constructor(url2) {
|
|
45553
|
+
super(`Figma answered 429 twice for ${url2}; wait and run again`);
|
|
45554
|
+
this.url = url2;
|
|
45555
|
+
this.name = "FigmaRateLimited";
|
|
45556
|
+
}
|
|
45557
|
+
};
|
|
45558
|
+
var FigmaRequestFailed = class extends Error {
|
|
45559
|
+
url;
|
|
45560
|
+
status;
|
|
45561
|
+
constructor(url2, status, body) {
|
|
45562
|
+
super(`Figma answered ${status} for ${url2}: ${body.slice(0, 200)}`);
|
|
45563
|
+
this.url = url2;
|
|
45564
|
+
this.status = status;
|
|
45565
|
+
this.name = "FigmaRequestFailed";
|
|
45566
|
+
}
|
|
45567
|
+
};
|
|
45568
|
+
var BASE = "https://api.figma.com/v1";
|
|
45569
|
+
var BATCH = 50;
|
|
45570
|
+
var MAX_WAIT_MS = 12e4;
|
|
45571
|
+
function createFigmaRest(options) {
|
|
45572
|
+
const send = options.fetch ?? globalThis.fetch;
|
|
45573
|
+
const sleep = options.sleep ?? ((ms) => new Promise((done) => setTimeout(done, ms)));
|
|
45574
|
+
const onCall = options.onCall ?? (() => void 0);
|
|
45575
|
+
async function call(url2) {
|
|
45576
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
45577
|
+
const res = await send(url2, { headers: { "X-Figma-Token": options.token } });
|
|
45578
|
+
onCall();
|
|
45579
|
+
if (res.status === 429) {
|
|
45580
|
+
if (attempt === 1)
|
|
45581
|
+
break;
|
|
45582
|
+
const seconds = Number(res.headers.get("Retry-After") ?? "60");
|
|
45583
|
+
await sleep(Math.min(Number.isFinite(seconds) ? seconds * 1e3 : 6e4, MAX_WAIT_MS));
|
|
45584
|
+
continue;
|
|
45585
|
+
}
|
|
45586
|
+
if (!res.ok)
|
|
45587
|
+
throw new FigmaRequestFailed(url2, res.status, await res.text());
|
|
45588
|
+
return await res.json();
|
|
45589
|
+
}
|
|
45590
|
+
throw new FigmaRateLimited(url2);
|
|
45591
|
+
}
|
|
45592
|
+
const chunks = (ids) => Array.from({ length: Math.ceil(ids.length / BATCH) }, (_, index) => ids.slice(index * BATCH, (index + 1) * BATCH));
|
|
45593
|
+
async function components(fileKey3) {
|
|
45594
|
+
const listed = await call(`${BASE}/files/${fileKey3}/components`);
|
|
45595
|
+
return listed.meta.components;
|
|
45596
|
+
}
|
|
45597
|
+
return {
|
|
45598
|
+
file: (fileKey3, depth) => call(`${BASE}/files/${fileKey3}?depth=${depth}`),
|
|
45599
|
+
async fileName(fileKey3) {
|
|
45600
|
+
const meta3 = await call(`${BASE}/files/${fileKey3}/meta`);
|
|
45601
|
+
return meta3.file.name;
|
|
45602
|
+
},
|
|
45603
|
+
async nodes(fileKey3, ids) {
|
|
45604
|
+
const merged = { version: "", nodes: {} };
|
|
45605
|
+
for (const chunk of chunks(ids)) {
|
|
45606
|
+
const part = await call(`${BASE}/files/${fileKey3}/nodes?ids=${encodeURIComponent(chunk.join(","))}`);
|
|
45607
|
+
merged.version = part.version;
|
|
45608
|
+
Object.assign(merged.nodes, part.nodes);
|
|
45609
|
+
}
|
|
45610
|
+
return merged;
|
|
45611
|
+
},
|
|
45612
|
+
async published(fileKey3) {
|
|
45613
|
+
const sets = await call(`${BASE}/files/${fileKey3}/component_sets`);
|
|
45614
|
+
return { sets: sets.meta.component_sets, components: await components(fileKey3) };
|
|
45615
|
+
},
|
|
45616
|
+
components,
|
|
45617
|
+
async images(fileKey3, ids) {
|
|
45618
|
+
const merged = {};
|
|
45619
|
+
for (const chunk of chunks(ids)) {
|
|
45620
|
+
const part = await call(`${BASE}/images/${fileKey3}?ids=${encodeURIComponent(chunk.join(","))}&format=png&scale=1`);
|
|
45621
|
+
Object.assign(merged, part.images);
|
|
45622
|
+
}
|
|
45623
|
+
return merged;
|
|
45624
|
+
}
|
|
45625
|
+
};
|
|
45626
|
+
}
|
|
45627
|
+
|
|
45783
45628
|
// packages/zaku/dist/lib/domain/documentation-measures.js
|
|
45784
45629
|
var COVER = {
|
|
45785
45630
|
page: "Thumbnail",
|
|
@@ -46357,7 +46202,7 @@ function outlineFrame(frame, where, ctx) {
|
|
|
46357
46202
|
const images2 = [];
|
|
46358
46203
|
const defaultNames = [];
|
|
46359
46204
|
const links = [];
|
|
46360
|
-
const
|
|
46205
|
+
const relative4 = (node2) => {
|
|
46361
46206
|
const box = node2.absoluteBoundingBox;
|
|
46362
46207
|
return box ? { x: box.x - origin.x, y: box.y - origin.y, width: box.width, height: box.height } : null;
|
|
46363
46208
|
};
|
|
@@ -46386,7 +46231,7 @@ function outlineFrame(frame, where, ctx) {
|
|
|
46386
46231
|
componentKey: ctx.components[child.componentId ?? ""]?.key ?? "",
|
|
46387
46232
|
component: component2,
|
|
46388
46233
|
interactive: ctx.interactive.has(component2),
|
|
46389
|
-
bounds:
|
|
46234
|
+
bounds: relative4(child)
|
|
46390
46235
|
});
|
|
46391
46236
|
} else if (child.type === "TEXT") {
|
|
46392
46237
|
instance.texts.push({
|
|
@@ -46427,7 +46272,7 @@ function outlineFrame(frame, where, ctx) {
|
|
|
46427
46272
|
texts: [],
|
|
46428
46273
|
interactive: ctx.interactive.has(component2),
|
|
46429
46274
|
local: meta3?.remote === false,
|
|
46430
|
-
bounds:
|
|
46275
|
+
bounds: relative4(node2),
|
|
46431
46276
|
sizing: {
|
|
46432
46277
|
horizontal: node2.layoutSizingHorizontal ?? "FIXED",
|
|
46433
46278
|
vertical: node2.layoutSizingVertical ?? "FIXED"
|
|
@@ -46609,7 +46454,7 @@ var screenOutlineSchema = external_exports.preprocess(legacyVersion, external_ex
|
|
|
46609
46454
|
mapDigest: external_exports.string(),
|
|
46610
46455
|
/** The version of each library snapshot the frames were read against, by key. */
|
|
46611
46456
|
libraryVersions: external_exports.record(external_exports.string(), external_exports.string()),
|
|
46612
|
-
/** The version of every product file zaku.yaml lists, when it lists them by
|
|
46457
|
+
/** The version of every product file zaku.yaml lists, when it lists them by family. */
|
|
46613
46458
|
fileVersions: external_exports.record(external_exports.string(), external_exports.string()).optional(),
|
|
46614
46459
|
frames: external_exports.array(frameOutlineSchema)
|
|
46615
46460
|
}).strict());
|
|
@@ -46619,6 +46464,7 @@ var unmappedSchema = external_exports.object({
|
|
|
46619
46464
|
/** A component drawn on a product page, which belongs in a Components library. */
|
|
46620
46465
|
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()
|
|
46621
46466
|
}).strict();
|
|
46467
|
+
var outlineFilesSchema = external_exports.object({ files: external_exports.array(external_exports.object({ key: external_exports.string(), name: external_exports.string() }).strict()) }).strict();
|
|
46622
46468
|
|
|
46623
46469
|
// packages/zaku/dist/lib/repositories/outlines.js
|
|
46624
46470
|
var FLOWS_DIR = "flows";
|
|
@@ -46638,12 +46484,12 @@ async function loadOutlines(dir) {
|
|
|
46638
46484
|
features = (await readdir3(dir, { withFileTypes: true })).filter((entry) => entry.isDirectory() && entry.name !== FLOWS_DIR).map((entry) => entry.name).sort();
|
|
46639
46485
|
} catch (error62) {
|
|
46640
46486
|
if (error62.code === "ENOENT")
|
|
46641
|
-
return { outlines, flows, unmapped: null, errors };
|
|
46487
|
+
return { outlines, flows, unmapped: null, files: null, errors };
|
|
46642
46488
|
throw error62;
|
|
46643
46489
|
}
|
|
46644
46490
|
for (const feature of features) {
|
|
46645
|
-
const
|
|
46646
|
-
for (const file2 of
|
|
46491
|
+
const files3 = (await readdir3(join5(dir, feature))).filter((name) => name.endsWith(".yaml")).sort();
|
|
46492
|
+
for (const file2 of files3) {
|
|
46647
46493
|
try {
|
|
46648
46494
|
outlines.push(await readDesignFile(join5(dir, feature, file2), screenOutlineSchema));
|
|
46649
46495
|
} catch (error62) {
|
|
@@ -46660,8 +46506,8 @@ async function loadOutlines(dir) {
|
|
|
46660
46506
|
throw error62;
|
|
46661
46507
|
});
|
|
46662
46508
|
for (const source of sources.sort()) {
|
|
46663
|
-
const
|
|
46664
|
-
for (const file2 of
|
|
46509
|
+
const files3 = (await readdir3(join5(dir, FLOWS_DIR, source))).filter((name) => name.endsWith(".yaml")).sort();
|
|
46510
|
+
for (const file2 of files3) {
|
|
46665
46511
|
try {
|
|
46666
46512
|
flows.push(await readDesignFile(join5(dir, FLOWS_DIR, source, file2), flowOutlineSchema));
|
|
46667
46513
|
} catch (error62) {
|
|
@@ -46681,7 +46527,16 @@ async function loadOutlines(dir) {
|
|
|
46681
46527
|
else
|
|
46682
46528
|
throw error62;
|
|
46683
46529
|
}
|
|
46684
|
-
|
|
46530
|
+
let files2 = null;
|
|
46531
|
+
try {
|
|
46532
|
+
files2 = await readOptionalDesignFile(join5(dir, "files.yaml"), outlineFilesSchema);
|
|
46533
|
+
} catch (error62) {
|
|
46534
|
+
if (error62 instanceof DesignFileInvalid)
|
|
46535
|
+
errors.push(error62);
|
|
46536
|
+
else
|
|
46537
|
+
throw error62;
|
|
46538
|
+
}
|
|
46539
|
+
return { outlines, flows, unmapped, files: files2, errors };
|
|
46685
46540
|
}
|
|
46686
46541
|
|
|
46687
46542
|
// packages/zaku/dist/lib/handlers/write-outline.js
|
|
@@ -46755,14 +46610,33 @@ function productFiles(config2) {
|
|
|
46755
46610
|
return config2.figma.product === void 0 ? [] : [{ key: config2.figma.product, targets: config2.targets }];
|
|
46756
46611
|
return graph.products.map((product) => ({
|
|
46757
46612
|
key: product.key,
|
|
46758
|
-
targets:
|
|
46613
|
+
targets: graph.targetsOf(product.family)
|
|
46759
46614
|
}));
|
|
46760
46615
|
}
|
|
46616
|
+
async function readFileNames(rest, config2, read) {
|
|
46617
|
+
const graph = designGraph(config2);
|
|
46618
|
+
const files2 = [];
|
|
46619
|
+
for (const file2 of [...graph.products, ...graph.prototypes]) {
|
|
46620
|
+
const name = read.get(file2.key);
|
|
46621
|
+
if (name !== void 0)
|
|
46622
|
+
files2.push({ key: file2.key, name });
|
|
46623
|
+
}
|
|
46624
|
+
for (const library of graph.libraries.filter((each) => each.layer === "components")) {
|
|
46625
|
+
try {
|
|
46626
|
+
files2.push({ key: library.key, name: await rest.fileName(library.key) });
|
|
46627
|
+
} catch (error62) {
|
|
46628
|
+
if (error62 instanceof FigmaRequestFailed && (error62.status === 403 || error62.status === 404))
|
|
46629
|
+
continue;
|
|
46630
|
+
throw error62;
|
|
46631
|
+
}
|
|
46632
|
+
}
|
|
46633
|
+
return { files: files2 };
|
|
46634
|
+
}
|
|
46761
46635
|
async function runOutline(options) {
|
|
46762
46636
|
const paths = designPaths(options.root);
|
|
46763
|
-
const config2 =
|
|
46764
|
-
const { libraries: listed, kits, products:
|
|
46765
|
-
const legacy = [listed, kits,
|
|
46637
|
+
const { config: config2 } = options;
|
|
46638
|
+
const { libraries: listed, kits, products: byFamily, prototypes: flows } = config2.figma;
|
|
46639
|
+
const legacy = [listed, kits, byFamily, flows].every((files2) => files2 === void 0);
|
|
46766
46640
|
const products = productFiles(config2);
|
|
46767
46641
|
if (products.length === 0)
|
|
46768
46642
|
throw new FigmaFileKeyMissing(legacy ? "figma.product" : "figma.products");
|
|
@@ -46775,6 +46649,7 @@ async function runOutline(options) {
|
|
|
46775
46649
|
const existing = await loadOutlines(paths.outline);
|
|
46776
46650
|
const prototypes = new Set(legacy ? config2.targets.map((target) => `${target.name} prototype`) : []);
|
|
46777
46651
|
const versions = {};
|
|
46652
|
+
const names = /* @__PURE__ */ new Map();
|
|
46778
46653
|
const flowPages = /* @__PURE__ */ new Map();
|
|
46779
46654
|
const flowFrame = (source, frame, targets) => {
|
|
46780
46655
|
const parsed = parseFrameName(frame.name, targets);
|
|
@@ -46792,6 +46667,7 @@ ${frame.page}`;
|
|
|
46792
46667
|
for (const product of products) {
|
|
46793
46668
|
const file2 = await options.rest.file(product.key, INDEX_DEPTH);
|
|
46794
46669
|
versions[product.key] = file2.version;
|
|
46670
|
+
names.set(product.key, file2.name);
|
|
46795
46671
|
const listed2 = listFrames(file2.document);
|
|
46796
46672
|
for (const frame of listed2.filter((candidate) => prototypes.has(candidate.page)))
|
|
46797
46673
|
flowFrame(product.key, frame, product.targets);
|
|
@@ -46815,13 +46691,18 @@ ${frame.page}`;
|
|
|
46815
46691
|
for (const file2 of legacy ? [] : graph.prototypes) {
|
|
46816
46692
|
const read = await options.rest.file(file2.key, INDEX_DEPTH);
|
|
46817
46693
|
versions[file2.key] = read.version;
|
|
46818
|
-
|
|
46694
|
+
names.set(file2.key, read.name);
|
|
46695
|
+
const targets = graph.targetsOf(file2.family);
|
|
46819
46696
|
for (const frame of listFrames(read.document).filter((candidate) => holdsScreens(candidate.page)))
|
|
46820
46697
|
flowFrame(file2.key, frame, targets);
|
|
46821
46698
|
}
|
|
46822
46699
|
unmapped.fileVersion = Object.values(versions).join(",");
|
|
46823
46700
|
if (!legacy)
|
|
46824
46701
|
unmapped.components = components;
|
|
46702
|
+
if (!legacy) {
|
|
46703
|
+
await mkdir2(paths.outline, { recursive: true });
|
|
46704
|
+
await writeFile3(paths.files, (0, import_yaml2.stringify)(await readFileNames(options.rest, config2, names)));
|
|
46705
|
+
}
|
|
46825
46706
|
const outlined = new Set(existing.outlines.flatMap((outline) => outline.frames.map((frame) => frame.nodeId)));
|
|
46826
46707
|
const drawnScreens = new Set([...resolved.values()].map(({ ref }) => `${ref.feature}/${ref.id}`));
|
|
46827
46708
|
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}`));
|
|
@@ -46942,7 +46823,7 @@ var WriteOutlineHandler = class WriteOutlineHandler2 {
|
|
|
46942
46823
|
this.rest = rest;
|
|
46943
46824
|
}
|
|
46944
46825
|
handle(command) {
|
|
46945
|
-
return runOutline({ root: command.root, rest: this.rest, frames: command.frames });
|
|
46826
|
+
return runOutline({ root: command.root, config: command.config, rest: this.rest, frames: command.frames });
|
|
46946
46827
|
}
|
|
46947
46828
|
};
|
|
46948
46829
|
WriteOutlineHandler = __decorate2([
|
|
@@ -46953,10 +46834,389 @@ WriteOutlineHandler = __decorate2([
|
|
|
46953
46834
|
// packages/zaku/dist/lib/handlers/write-schemas.js
|
|
46954
46835
|
var import_tsyringe5 = __toESM(require_cjs(), 1);
|
|
46955
46836
|
|
|
46837
|
+
// packages/zaku/dist/lib/schema/zaku-config.js
|
|
46838
|
+
import { posix } from "node:path";
|
|
46839
|
+
|
|
46840
|
+
// packages/zaku/dist/lib/domain/copy-defaults.js
|
|
46841
|
+
var DEFAULT_COPY = { locales: ["en"], currencies: [] };
|
|
46842
|
+
|
|
46843
|
+
// packages/zaku/dist/lib/schema/zaku-config.js
|
|
46844
|
+
var PLATFORM_FAMILIES = ["web", "ios", "android", "macos", "windows", "gnome", "kde"];
|
|
46845
|
+
var LAYERS = ["foundations", "components"];
|
|
46846
|
+
var BRANCHES = ["ui", "native"];
|
|
46847
|
+
var DEFAULT_INTERACTIVE = [
|
|
46848
|
+
"Button",
|
|
46849
|
+
"Button Group",
|
|
46850
|
+
"Checkbox",
|
|
46851
|
+
"Combobox",
|
|
46852
|
+
"Dropdown Menu",
|
|
46853
|
+
"Input",
|
|
46854
|
+
"Input Group",
|
|
46855
|
+
"Input OTP",
|
|
46856
|
+
"Native Select",
|
|
46857
|
+
"Pagination",
|
|
46858
|
+
"Radio Group",
|
|
46859
|
+
"Select",
|
|
46860
|
+
"Slider",
|
|
46861
|
+
"Switch",
|
|
46862
|
+
"Tabs",
|
|
46863
|
+
"Textarea",
|
|
46864
|
+
"Toggle",
|
|
46865
|
+
"Toggle Group"
|
|
46866
|
+
];
|
|
46867
|
+
var id = external_exports.string().regex(/^[a-z][a-z0-9-]*$/, "lowercase letters, digits and dashes, starting with a letter");
|
|
46868
|
+
var targetSchema = external_exports.object({
|
|
46869
|
+
id,
|
|
46870
|
+
family: external_exports.enum(PLATFORM_FAMILIES),
|
|
46871
|
+
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"),
|
|
46872
|
+
/** The frame size every frame of this target is drawn at; the frame check compares it. */
|
|
46873
|
+
size: external_exports.object({ width: external_exports.number().positive(), height: external_exports.number().positive() }).strict().optional(),
|
|
46874
|
+
/** The renderer whose libraries its frames draw from; `defaultBranch` in the design graph gives it when left out. */
|
|
46875
|
+
branch: external_exports.enum(BRANCHES).optional()
|
|
46876
|
+
}).strict();
|
|
46877
|
+
var DEFAULT_SYSTEM_BARS = {
|
|
46878
|
+
web: [],
|
|
46879
|
+
ios: [["Status Bar"], ["Home Indicator"]],
|
|
46880
|
+
android: [["Status Bar"], ["Navigation Bar", "Gesture Handle"]],
|
|
46881
|
+
macos: [["Window Controls"]],
|
|
46882
|
+
windows: [["Title Bar"]],
|
|
46883
|
+
gnome: [["Header Bar"]],
|
|
46884
|
+
kde: [["Title Bar"]]
|
|
46885
|
+
};
|
|
46886
|
+
function systemBarNames(config2) {
|
|
46887
|
+
const bars = { ...DEFAULT_SYSTEM_BARS, ...config2.systemBars };
|
|
46888
|
+
return new Set(Object.values(bars).flat(2));
|
|
46889
|
+
}
|
|
46890
|
+
var budgetSchema = external_exports.object({
|
|
46891
|
+
mcpPerDay: external_exports.number().int().positive().default(200),
|
|
46892
|
+
mcpPerRun: external_exports.number().int().positive().default(30),
|
|
46893
|
+
reserve: external_exports.number().min(0).max(1).default(0.2)
|
|
46894
|
+
}).strict();
|
|
46895
|
+
var fileKey = external_exports.string().min(1);
|
|
46896
|
+
var kitSchema = external_exports.object({ key: fileKey, family: external_exports.enum(PLATFORM_FAMILIES) }).strict();
|
|
46897
|
+
var librarySchema = external_exports.object({
|
|
46898
|
+
key: fileKey,
|
|
46899
|
+
layer: external_exports.enum(LAYERS),
|
|
46900
|
+
branches: external_exports.array(external_exports.enum(BRANCHES)).min(1),
|
|
46901
|
+
/** The libraries and kits this one is built on, by key. */
|
|
46902
|
+
extends: external_exports.array(fileKey).default([])
|
|
46903
|
+
}).strict();
|
|
46904
|
+
var productSchema = external_exports.object({ key: fileKey, family: external_exports.enum(PLATFORM_FAMILIES) }).strict();
|
|
46905
|
+
var prototypeSchema = external_exports.object({ key: fileKey, family: external_exports.enum(PLATFORM_FAMILIES) }).strict();
|
|
46906
|
+
var files = external_exports.object({
|
|
46907
|
+
library: fileKey.optional(),
|
|
46908
|
+
product: fileKey.optional(),
|
|
46909
|
+
kits: external_exports.array(kitSchema).optional(),
|
|
46910
|
+
libraries: external_exports.array(librarySchema).optional(),
|
|
46911
|
+
products: external_exports.array(productSchema).optional(),
|
|
46912
|
+
prototypes: external_exports.array(prototypeSchema).optional()
|
|
46913
|
+
}).strict();
|
|
46914
|
+
function byRole(figma) {
|
|
46915
|
+
return [figma.kits, figma.libraries, figma.products, figma.prototypes].some((list) => list !== void 0);
|
|
46916
|
+
}
|
|
46917
|
+
var shadcnSystem = external_exports.object({
|
|
46918
|
+
preset: external_exports.string().min(1),
|
|
46919
|
+
/** The stylesheet `zaku tokens` reads, relative to the directory of the workspace config. */
|
|
46920
|
+
css: external_exports.string().min(1).optional()
|
|
46921
|
+
}).strict();
|
|
46922
|
+
var tokenFiles = external_exports.array(external_exports.string().min(1)).min(1);
|
|
46923
|
+
var resolverInputs = external_exports.record(external_exports.string(), external_exports.string());
|
|
46924
|
+
var dtcgSystem = external_exports.object({
|
|
46925
|
+
resolver: external_exports.string().min(1).optional(),
|
|
46926
|
+
light: external_exports.union([tokenFiles, resolverInputs]),
|
|
46927
|
+
dark: external_exports.union([tokenFiles, resolverInputs]),
|
|
46928
|
+
/** The group whose tokens are the colour roles, and the one whose tokens are the radius steps. */
|
|
46929
|
+
colors: external_exports.string().min(1).default("color"),
|
|
46930
|
+
radii: external_exports.string().min(1).default("radius"),
|
|
46931
|
+
/** Foreground and background token pairs a text is read in, each needing 4.5:1. */
|
|
46932
|
+
contrast: external_exports.array(external_exports.tuple([external_exports.string().min(1), external_exports.string().min(1)])).default([])
|
|
46933
|
+
}).strict().superRefine((dtcg, ctx) => {
|
|
46934
|
+
for (const scheme of ["light", "dark"]) {
|
|
46935
|
+
const files2 = Array.isArray(dtcg[scheme]);
|
|
46936
|
+
if (dtcg.resolver !== void 0 && files2) {
|
|
46937
|
+
ctx.addIssue({
|
|
46938
|
+
code: "custom",
|
|
46939
|
+
path: [scheme],
|
|
46940
|
+
message: "with a resolver, name the modifier contexts, not files"
|
|
46941
|
+
});
|
|
46942
|
+
}
|
|
46943
|
+
if (dtcg.resolver === void 0 && !files2) {
|
|
46944
|
+
ctx.addIssue({
|
|
46945
|
+
code: "custom",
|
|
46946
|
+
path: [scheme],
|
|
46947
|
+
message: "without a resolver, list the token files"
|
|
46948
|
+
});
|
|
46949
|
+
}
|
|
46950
|
+
}
|
|
46951
|
+
});
|
|
46952
|
+
var designSystemSchema = external_exports.union([
|
|
46953
|
+
external_exports.object({ shadcn: shadcnSystem }).strict(),
|
|
46954
|
+
external_exports.object({ dtcg: dtcgSystem }).strict()
|
|
46955
|
+
]);
|
|
46956
|
+
var recipeSchema = external_exports.object({
|
|
46957
|
+
url: external_exports.url().optional(),
|
|
46958
|
+
dark: external_exports.enum(["class", "media"]).default("class"),
|
|
46959
|
+
darkClass: external_exports.string().min(1).default("dark")
|
|
46960
|
+
}).strict();
|
|
46961
|
+
function writtenInAScript(tag) {
|
|
46962
|
+
try {
|
|
46963
|
+
return new Intl.Locale(tag).maximize().script !== void 0;
|
|
46964
|
+
} catch {
|
|
46965
|
+
return false;
|
|
46966
|
+
}
|
|
46967
|
+
}
|
|
46968
|
+
var copySchema = external_exports.object({
|
|
46969
|
+
locales: external_exports.array(external_exports.string().refine(writtenInAScript, "a BCP 47 language tag, such as en or vi")).min(1).default(["en"]),
|
|
46970
|
+
currencies: external_exports.array(external_exports.string().refine((code) => Intl.supportedValuesOf("currency").includes(code), "an ISO 4217 code, such as VND or USD")).default([])
|
|
46971
|
+
}).strict();
|
|
46972
|
+
var configShape = external_exports.object({
|
|
46973
|
+
product: external_exports.string().min(1),
|
|
46974
|
+
designSystem: designSystemSchema,
|
|
46975
|
+
figma: files.default({}),
|
|
46976
|
+
targets: external_exports.array(targetSchema).min(1),
|
|
46977
|
+
modes: external_exports.record(external_exports.string(), external_exports.string()).default({}),
|
|
46978
|
+
interactive: external_exports.array(external_exports.string().min(1)).default([...DEFAULT_INTERACTIVE]),
|
|
46979
|
+
/** The bars of the families whose kit names them its own way; every family left out keeps its default. */
|
|
46980
|
+
systemBars: external_exports.partialRecord(external_exports.enum(PLATFORM_FAMILIES), external_exports.array(external_exports.array(external_exports.string().min(1)).min(1))).optional(),
|
|
46981
|
+
budget: budgetSchema.default({ mcpPerDay: 200, mcpPerRun: 30, reserve: 0.2 }),
|
|
46982
|
+
recipe: recipeSchema.optional(),
|
|
46983
|
+
copy: copySchema.default(DEFAULT_COPY)
|
|
46984
|
+
}).strict();
|
|
46985
|
+
var zakuConfigSchema = configShape.superRefine((config2, ctx) => {
|
|
46986
|
+
for (const key of ["id", "name"]) {
|
|
46987
|
+
const seen = /* @__PURE__ */ new Set();
|
|
46988
|
+
config2.targets.forEach((target, index) => {
|
|
46989
|
+
if (seen.has(target[key])) {
|
|
46990
|
+
ctx.addIssue({
|
|
46991
|
+
code: "custom",
|
|
46992
|
+
path: ["targets", index, key],
|
|
46993
|
+
message: `a second target with ${key} ${target[key]}`
|
|
46994
|
+
});
|
|
46995
|
+
}
|
|
46996
|
+
seen.add(target[key]);
|
|
46997
|
+
});
|
|
46998
|
+
}
|
|
46999
|
+
if (byRole(config2.figma))
|
|
47000
|
+
refineFilesByRole(config2, ctx);
|
|
47001
|
+
});
|
|
47002
|
+
function refineFilesByRole(config2, ctx) {
|
|
47003
|
+
const { figma } = config2;
|
|
47004
|
+
if (figma.library !== void 0 || figma.product !== void 0) {
|
|
47005
|
+
ctx.addIssue({
|
|
47006
|
+
code: "custom",
|
|
47007
|
+
path: ["figma"],
|
|
47008
|
+
message: "figma.library and figma.product describe one library and one product; list files by role instead"
|
|
47009
|
+
});
|
|
47010
|
+
}
|
|
47011
|
+
const kits = figma.kits ?? [];
|
|
47012
|
+
const libraries = figma.libraries ?? [];
|
|
47013
|
+
const products = figma.products ?? [];
|
|
47014
|
+
const seen = /* @__PURE__ */ new Set();
|
|
47015
|
+
const lists = [
|
|
47016
|
+
["kits", kits],
|
|
47017
|
+
["libraries", libraries],
|
|
47018
|
+
["products", products],
|
|
47019
|
+
["prototypes", figma.prototypes ?? []]
|
|
47020
|
+
];
|
|
47021
|
+
for (const [list, entries] of lists) {
|
|
47022
|
+
entries.forEach((entry, index) => {
|
|
47023
|
+
if (seen.has(entry.key))
|
|
47024
|
+
ctx.addIssue({
|
|
47025
|
+
code: "custom",
|
|
47026
|
+
path: ["figma", list, index, "key"],
|
|
47027
|
+
message: `a second file with key ${entry.key}`
|
|
47028
|
+
});
|
|
47029
|
+
seen.add(entry.key);
|
|
47030
|
+
});
|
|
47031
|
+
}
|
|
47032
|
+
const byKey = new Map(libraries.map((library) => [library.key, library]));
|
|
47033
|
+
const kitKeys = new Set(kits.map((kit) => kit.key));
|
|
47034
|
+
libraries.forEach((library, index) => {
|
|
47035
|
+
const path2 = ["figma", "libraries", index, "extends"];
|
|
47036
|
+
for (const key of library.extends) {
|
|
47037
|
+
const base = byKey.get(key);
|
|
47038
|
+
if (!base && !kitKeys.has(key)) {
|
|
47039
|
+
ctx.addIssue({
|
|
47040
|
+
code: "custom",
|
|
47041
|
+
path: path2,
|
|
47042
|
+
message: `${library.key} extends ${key}, which is no library or kit listed`
|
|
47043
|
+
});
|
|
47044
|
+
} else if (base?.layer === "components" && library.layer === "foundations") {
|
|
47045
|
+
ctx.addIssue({ code: "custom", path: path2, message: `foundations ${library.key} extends components ${key}` });
|
|
47046
|
+
} else if (base && !base.branches.some((branch) => library.branches.includes(branch))) {
|
|
47047
|
+
ctx.addIssue({
|
|
47048
|
+
code: "custom",
|
|
47049
|
+
path: path2,
|
|
47050
|
+
message: `${library.key} extends ${key}, which holds none of its branches`
|
|
47051
|
+
});
|
|
47052
|
+
}
|
|
47053
|
+
}
|
|
47054
|
+
});
|
|
47055
|
+
const cycle = findCycle(libraries);
|
|
47056
|
+
if (cycle)
|
|
47057
|
+
ctx.addIssue({ code: "custom", path: ["figma", "libraries"], message: `extends comes back: ${cycle}` });
|
|
47058
|
+
for (const [list, entries] of [
|
|
47059
|
+
["products", products],
|
|
47060
|
+
["prototypes", figma.prototypes ?? []]
|
|
47061
|
+
]) {
|
|
47062
|
+
const families2 = /* @__PURE__ */ new Set();
|
|
47063
|
+
entries.forEach((entry, index) => {
|
|
47064
|
+
if (families2.has(entry.family))
|
|
47065
|
+
ctx.addIssue({
|
|
47066
|
+
code: "custom",
|
|
47067
|
+
path: ["figma", list, index, "family"],
|
|
47068
|
+
message: `a second ${list === "products" ? "product" : "prototype"} file for ${entry.family}`
|
|
47069
|
+
});
|
|
47070
|
+
families2.add(entry.family);
|
|
47071
|
+
});
|
|
47072
|
+
}
|
|
47073
|
+
(figma.prototypes ?? []).forEach((prototype2, index) => {
|
|
47074
|
+
if (!products.some((product) => product.family === prototype2.family))
|
|
47075
|
+
ctx.addIssue({
|
|
47076
|
+
code: "custom",
|
|
47077
|
+
path: ["figma", "prototypes", index, "family"],
|
|
47078
|
+
message: `no product file for ${prototype2.family} to copy its frames from`
|
|
47079
|
+
});
|
|
47080
|
+
});
|
|
47081
|
+
config2.targets.forEach((target, index) => {
|
|
47082
|
+
const branch = target.branch ?? defaultBranch(target.family);
|
|
47083
|
+
const path2 = ["targets", index, "branch"];
|
|
47084
|
+
if (branch === void 0) {
|
|
47085
|
+
ctx.addIssue({ code: "custom", path: path2, message: `a ${target.family} target names its branch, ui or native` });
|
|
47086
|
+
} else if (libraries.length > 0 && !libraries.some((library) => library.branches.includes(branch))) {
|
|
47087
|
+
ctx.addIssue({ code: "custom", path: path2, message: `no library holds the ${branch} branch` });
|
|
47088
|
+
}
|
|
47089
|
+
});
|
|
47090
|
+
}
|
|
47091
|
+
function findCycle(libraries) {
|
|
47092
|
+
const byKey = new Map(libraries.map((library) => [library.key, library]));
|
|
47093
|
+
const visit2 = (key, path2) => {
|
|
47094
|
+
if (path2.includes(key))
|
|
47095
|
+
return [...path2.slice(path2.indexOf(key)), key].join(" -> ");
|
|
47096
|
+
for (const next of byKey.get(key)?.extends ?? []) {
|
|
47097
|
+
const found = visit2(next, [...path2, key]);
|
|
47098
|
+
if (found)
|
|
47099
|
+
return found;
|
|
47100
|
+
}
|
|
47101
|
+
return void 0;
|
|
47102
|
+
};
|
|
47103
|
+
for (const library of libraries) {
|
|
47104
|
+
const found = visit2(library.key, []);
|
|
47105
|
+
if (found)
|
|
47106
|
+
return found;
|
|
47107
|
+
}
|
|
47108
|
+
return void 0;
|
|
47109
|
+
}
|
|
47110
|
+
var SHARED_KEYS = ["designSystem", "modes", "copy", "interactive", "systemBars", "budget"];
|
|
47111
|
+
var sharedShape = {
|
|
47112
|
+
designSystem: designSystemSchema.optional(),
|
|
47113
|
+
modes: configShape.shape.modes.unwrap().optional(),
|
|
47114
|
+
copy: copySchema.optional(),
|
|
47115
|
+
interactive: configShape.shape.interactive.unwrap().optional(),
|
|
47116
|
+
systemBars: configShape.shape.systemBars,
|
|
47117
|
+
budget: budgetSchema.optional()
|
|
47118
|
+
};
|
|
47119
|
+
var PRODUCT_NAME = /^[A-Z0-9][A-Za-z0-9]*( [A-Z0-9][A-Za-z0-9]*)*$/;
|
|
47120
|
+
var workspaceProduct = external_exports.object({
|
|
47121
|
+
/** Title-case ASCII words: what people call the product and what its Figma files are named for. */
|
|
47122
|
+
name: external_exports.string().regex(PRODUCT_NAME, "title-case words of ASCII letters and digits, such as Back Office"),
|
|
47123
|
+
/** The directory of the product's design, relative to the config and inside its directory. */
|
|
47124
|
+
root: external_exports.string().min(1)
|
|
47125
|
+
}).strict();
|
|
47126
|
+
function cleanRoot(root) {
|
|
47127
|
+
if (root.includes("\\"))
|
|
47128
|
+
return { problem: "use forward slashes" };
|
|
47129
|
+
if (root.startsWith("/"))
|
|
47130
|
+
return { problem: "a root is relative to the config, not absolute" };
|
|
47131
|
+
const path2 = posix.normalize(root).replace(/\/$/, "");
|
|
47132
|
+
if (path2 === ".." || path2.startsWith("../"))
|
|
47133
|
+
return { problem: "a root stays inside the config's directory" };
|
|
47134
|
+
return { path: path2 };
|
|
47135
|
+
}
|
|
47136
|
+
function overlaps(a, b) {
|
|
47137
|
+
return a === "." || b === "." || a === b || a.startsWith(`${b}/`) || b.startsWith(`${a}/`);
|
|
47138
|
+
}
|
|
47139
|
+
var workspaceConfigSchema = external_exports.object({
|
|
47140
|
+
...sharedShape,
|
|
47141
|
+
products: external_exports.array(workspaceProduct).min(1).optional(),
|
|
47142
|
+
product: external_exports.string().min(1).optional(),
|
|
47143
|
+
figma: files.optional(),
|
|
47144
|
+
targets: external_exports.array(targetSchema).optional(),
|
|
47145
|
+
recipe: recipeSchema.optional()
|
|
47146
|
+
}).strict().superRefine((config2, ctx) => {
|
|
47147
|
+
const { products, ...single } = config2;
|
|
47148
|
+
if (products === void 0) {
|
|
47149
|
+
const result = zakuConfigSchema.safeParse(single);
|
|
47150
|
+
if (!result.success) {
|
|
47151
|
+
for (const issue2 of result.error.issues) {
|
|
47152
|
+
ctx.addIssue({ code: "custom", path: issue2.path, message: issue2.message });
|
|
47153
|
+
}
|
|
47154
|
+
}
|
|
47155
|
+
return;
|
|
47156
|
+
}
|
|
47157
|
+
for (const key of ["product", "figma", "targets", "recipe"]) {
|
|
47158
|
+
if (config2[key] !== void 0) {
|
|
47159
|
+
ctx.addIssue({
|
|
47160
|
+
code: "custom",
|
|
47161
|
+
path: [key],
|
|
47162
|
+
message: `a workspace that lists products keeps ${key} in each product`
|
|
47163
|
+
});
|
|
47164
|
+
}
|
|
47165
|
+
}
|
|
47166
|
+
const names = /* @__PURE__ */ new Set();
|
|
47167
|
+
const roots = [];
|
|
47168
|
+
products.forEach((product, index) => {
|
|
47169
|
+
if (names.has(product.name)) {
|
|
47170
|
+
ctx.addIssue({
|
|
47171
|
+
code: "custom",
|
|
47172
|
+
path: ["products", index, "name"],
|
|
47173
|
+
message: `a second product named ${product.name}`
|
|
47174
|
+
});
|
|
47175
|
+
}
|
|
47176
|
+
names.add(product.name);
|
|
47177
|
+
const root = cleanRoot(product.root);
|
|
47178
|
+
if ("problem" in root) {
|
|
47179
|
+
ctx.addIssue({ code: "custom", path: ["products", index, "root"], message: root.problem });
|
|
47180
|
+
return;
|
|
47181
|
+
}
|
|
47182
|
+
const clash = roots.find((other) => overlaps(other, root.path));
|
|
47183
|
+
if (clash !== void 0) {
|
|
47184
|
+
ctx.addIssue({
|
|
47185
|
+
code: "custom",
|
|
47186
|
+
path: ["products", index, "root"],
|
|
47187
|
+
message: `${product.root} overlaps ${clash}, which another product holds`
|
|
47188
|
+
});
|
|
47189
|
+
}
|
|
47190
|
+
roots.push(root.path);
|
|
47191
|
+
});
|
|
47192
|
+
});
|
|
47193
|
+
var productConfigSchema = external_exports.object({
|
|
47194
|
+
...sharedShape,
|
|
47195
|
+
figma: files.default({}),
|
|
47196
|
+
targets: external_exports.array(targetSchema).min(1),
|
|
47197
|
+
recipe: recipeSchema.optional()
|
|
47198
|
+
}).strict();
|
|
47199
|
+
function mergeProductConfig(shared, name, product) {
|
|
47200
|
+
const own2 = productConfigSchema.safeParse(product);
|
|
47201
|
+
if (!own2.success)
|
|
47202
|
+
throw new DesignFileInvalid(`zaku.yaml of ${name}`, issueLines(own2.error));
|
|
47203
|
+
const merged = { ...own2.data, product: name };
|
|
47204
|
+
for (const key of SHARED_KEYS)
|
|
47205
|
+
merged[key] = own2.data[key] ?? shared[key];
|
|
47206
|
+
const result = zakuConfigSchema.safeParse(merged);
|
|
47207
|
+
if (!result.success)
|
|
47208
|
+
throw new DesignFileInvalid(`zaku.yaml of ${name}`, issueLines(result.error));
|
|
47209
|
+
return result.data;
|
|
47210
|
+
}
|
|
47211
|
+
function issueLines(error62) {
|
|
47212
|
+
return error62.issues.map((issue2) => `${issue2.path.map(String).join(".") || "(root)"}: ${issue2.message}`);
|
|
47213
|
+
}
|
|
47214
|
+
|
|
46956
47215
|
// packages/zaku/dist/lib/schema/json-schemas.js
|
|
46957
47216
|
function designJsonSchemas() {
|
|
46958
47217
|
return {
|
|
46959
47218
|
"zaku.schema.json": external_exports.toJSONSchema(zakuConfigSchema, { io: "input" }),
|
|
47219
|
+
"zaku-config.schema.json": external_exports.toJSONSchema(workspaceConfigSchema, { io: "input" }),
|
|
46960
47220
|
"map.schema.json": external_exports.toJSONSchema(featureMapSchema, { io: "input" })
|
|
46961
47221
|
};
|
|
46962
47222
|
}
|
|
@@ -47000,22 +47260,8 @@ RecordBudgetCallsHandler = __decorate2([
|
|
|
47000
47260
|
__param2(0, (0, import_tsyringe6.inject)(TOKENS.BUDGET_LEDGER))
|
|
47001
47261
|
], RecordBudgetCallsHandler);
|
|
47002
47262
|
|
|
47003
|
-
// packages/zaku/dist/lib/repositories/design-config-repository.js
|
|
47004
|
-
var import_tsyringe7 = __toESM(require_cjs(), 1);
|
|
47005
|
-
var DesignConfigRepository = class DesignConfigRepository2 {
|
|
47006
|
-
read(root) {
|
|
47007
|
-
return readDesignFile(designPaths(root).config, zakuConfigSchema);
|
|
47008
|
-
}
|
|
47009
|
-
readOptional(root) {
|
|
47010
|
-
return readOptionalDesignFile(designPaths(root).config, zakuConfigSchema);
|
|
47011
|
-
}
|
|
47012
|
-
};
|
|
47013
|
-
DesignConfigRepository = __decorate2([
|
|
47014
|
-
(0, import_tsyringe7.injectable)({ token: TOKENS.DESIGN_CONFIG_REPOSITORY })
|
|
47015
|
-
], DesignConfigRepository);
|
|
47016
|
-
|
|
47017
47263
|
// packages/zaku/dist/lib/repositories/token-document-repository.js
|
|
47018
|
-
var
|
|
47264
|
+
var import_tsyringe7 = __toESM(require_cjs(), 1);
|
|
47019
47265
|
var TokenDocumentRepository = class TokenDocumentRepository2 {
|
|
47020
47266
|
async save(root, doc) {
|
|
47021
47267
|
const path2 = designPaths(root).tokens;
|
|
@@ -47024,11 +47270,11 @@ var TokenDocumentRepository = class TokenDocumentRepository2 {
|
|
|
47024
47270
|
}
|
|
47025
47271
|
};
|
|
47026
47272
|
TokenDocumentRepository = __decorate2([
|
|
47027
|
-
(0,
|
|
47273
|
+
(0, import_tsyringe7.injectable)({ token: TOKENS.TOKEN_DOCUMENT_REPOSITORY })
|
|
47028
47274
|
], TokenDocumentRepository);
|
|
47029
47275
|
|
|
47030
47276
|
// packages/zaku/dist/lib/repositories/recipe-repository.js
|
|
47031
|
-
var
|
|
47277
|
+
var import_tsyringe8 = __toESM(require_cjs(), 1);
|
|
47032
47278
|
var RecipeRepository = class RecipeRepository2 {
|
|
47033
47279
|
async save(root, doc) {
|
|
47034
47280
|
const path2 = designPaths(root).recipe;
|
|
@@ -47037,11 +47283,11 @@ var RecipeRepository = class RecipeRepository2 {
|
|
|
47037
47283
|
}
|
|
47038
47284
|
};
|
|
47039
47285
|
RecipeRepository = __decorate2([
|
|
47040
|
-
(0,
|
|
47286
|
+
(0, import_tsyringe8.injectable)({ token: TOKENS.RECIPE_REPOSITORY })
|
|
47041
47287
|
], RecipeRepository);
|
|
47042
47288
|
|
|
47043
47289
|
// packages/zaku/dist/lib/repositories/json-schema-files.js
|
|
47044
|
-
var
|
|
47290
|
+
var import_tsyringe9 = __toESM(require_cjs(), 1);
|
|
47045
47291
|
import { mkdir as mkdir3 } from "node:fs/promises";
|
|
47046
47292
|
import { join as join7 } from "node:path";
|
|
47047
47293
|
var JsonSchemaFiles = class JsonSchemaFiles2 {
|
|
@@ -47057,11 +47303,11 @@ var JsonSchemaFiles = class JsonSchemaFiles2 {
|
|
|
47057
47303
|
}
|
|
47058
47304
|
};
|
|
47059
47305
|
JsonSchemaFiles = __decorate2([
|
|
47060
|
-
(0,
|
|
47306
|
+
(0, import_tsyringe9.injectable)({ token: TOKENS.JSON_SCHEMA_FILES })
|
|
47061
47307
|
], JsonSchemaFiles);
|
|
47062
47308
|
|
|
47063
47309
|
// packages/zaku/dist/lib/repositories/source-files.js
|
|
47064
|
-
var
|
|
47310
|
+
var import_tsyringe10 = __toESM(require_cjs(), 1);
|
|
47065
47311
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
47066
47312
|
var SourceFiles = class SourceFiles2 {
|
|
47067
47313
|
readText(path2) {
|
|
@@ -47072,7 +47318,7 @@ var SourceFiles = class SourceFiles2 {
|
|
|
47072
47318
|
}
|
|
47073
47319
|
};
|
|
47074
47320
|
SourceFiles = __decorate2([
|
|
47075
|
-
(0,
|
|
47321
|
+
(0, import_tsyringe10.injectable)({ token: TOKENS.SOURCE_FILES })
|
|
47076
47322
|
], SourceFiles);
|
|
47077
47323
|
|
|
47078
47324
|
// packages/zaku/dist/lib/repositories/budget-ledger.js
|
|
@@ -47159,7 +47405,8 @@ function printGraph(config2, snapshots) {
|
|
|
47159
47405
|
...graph.kitsFor(target).map((kit) => `${kit.key} ${kit.family} kit`)
|
|
47160
47406
|
];
|
|
47161
47407
|
const branch = graph.branchOf(target);
|
|
47162
|
-
|
|
47408
|
+
const product = graph.products.find((file2) => file2.family === target.family)?.key;
|
|
47409
|
+
lines.push(` ${target.name} (${target.id}, ${branch ? `branch ${branch}` : "no branch"}, ${product ? `product ${product}` : "no product"}): ${files2.join(", ") || "nothing"}`);
|
|
47163
47410
|
}
|
|
47164
47411
|
lines.push("files");
|
|
47165
47412
|
const extendedBy = (key) => graph.libraries.filter((library) => library.extends.includes(key)).map((library) => library.key).join(", ") || "nothing";
|
|
@@ -47173,81 +47420,6 @@ function printGraph(config2, snapshots) {
|
|
|
47173
47420
|
return lines;
|
|
47174
47421
|
}
|
|
47175
47422
|
|
|
47176
|
-
// packages/zaku/dist/lib/adapters/figma-rest.js
|
|
47177
|
-
var FigmaRateLimited = class extends Error {
|
|
47178
|
-
url;
|
|
47179
|
-
constructor(url2) {
|
|
47180
|
-
super(`Figma answered 429 twice for ${url2}; wait and run again`);
|
|
47181
|
-
this.url = url2;
|
|
47182
|
-
this.name = "FigmaRateLimited";
|
|
47183
|
-
}
|
|
47184
|
-
};
|
|
47185
|
-
var FigmaRequestFailed = class extends Error {
|
|
47186
|
-
url;
|
|
47187
|
-
status;
|
|
47188
|
-
constructor(url2, status, body) {
|
|
47189
|
-
super(`Figma answered ${status} for ${url2}: ${body.slice(0, 200)}`);
|
|
47190
|
-
this.url = url2;
|
|
47191
|
-
this.status = status;
|
|
47192
|
-
this.name = "FigmaRequestFailed";
|
|
47193
|
-
}
|
|
47194
|
-
};
|
|
47195
|
-
var BASE = "https://api.figma.com/v1";
|
|
47196
|
-
var BATCH = 50;
|
|
47197
|
-
var MAX_WAIT_MS = 12e4;
|
|
47198
|
-
function createFigmaRest(options) {
|
|
47199
|
-
const send = options.fetch ?? globalThis.fetch;
|
|
47200
|
-
const sleep = options.sleep ?? ((ms) => new Promise((done) => setTimeout(done, ms)));
|
|
47201
|
-
const onCall = options.onCall ?? (() => void 0);
|
|
47202
|
-
async function call(url2) {
|
|
47203
|
-
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
47204
|
-
const res = await send(url2, { headers: { "X-Figma-Token": options.token } });
|
|
47205
|
-
onCall();
|
|
47206
|
-
if (res.status === 429) {
|
|
47207
|
-
if (attempt === 1)
|
|
47208
|
-
break;
|
|
47209
|
-
const seconds = Number(res.headers.get("Retry-After") ?? "60");
|
|
47210
|
-
await sleep(Math.min(Number.isFinite(seconds) ? seconds * 1e3 : 6e4, MAX_WAIT_MS));
|
|
47211
|
-
continue;
|
|
47212
|
-
}
|
|
47213
|
-
if (!res.ok)
|
|
47214
|
-
throw new FigmaRequestFailed(url2, res.status, await res.text());
|
|
47215
|
-
return await res.json();
|
|
47216
|
-
}
|
|
47217
|
-
throw new FigmaRateLimited(url2);
|
|
47218
|
-
}
|
|
47219
|
-
const chunks = (ids) => Array.from({ length: Math.ceil(ids.length / BATCH) }, (_, index) => ids.slice(index * BATCH, (index + 1) * BATCH));
|
|
47220
|
-
async function components(fileKey3) {
|
|
47221
|
-
const listed = await call(`${BASE}/files/${fileKey3}/components`);
|
|
47222
|
-
return listed.meta.components;
|
|
47223
|
-
}
|
|
47224
|
-
return {
|
|
47225
|
-
file: (fileKey3, depth) => call(`${BASE}/files/${fileKey3}?depth=${depth}`),
|
|
47226
|
-
async nodes(fileKey3, ids) {
|
|
47227
|
-
const merged = { version: "", nodes: {} };
|
|
47228
|
-
for (const chunk of chunks(ids)) {
|
|
47229
|
-
const part = await call(`${BASE}/files/${fileKey3}/nodes?ids=${encodeURIComponent(chunk.join(","))}`);
|
|
47230
|
-
merged.version = part.version;
|
|
47231
|
-
Object.assign(merged.nodes, part.nodes);
|
|
47232
|
-
}
|
|
47233
|
-
return merged;
|
|
47234
|
-
},
|
|
47235
|
-
async published(fileKey3) {
|
|
47236
|
-
const sets = await call(`${BASE}/files/${fileKey3}/component_sets`);
|
|
47237
|
-
return { sets: sets.meta.component_sets, components: await components(fileKey3) };
|
|
47238
|
-
},
|
|
47239
|
-
components,
|
|
47240
|
-
async images(fileKey3, ids) {
|
|
47241
|
-
const merged = {};
|
|
47242
|
-
for (const chunk of chunks(ids)) {
|
|
47243
|
-
const part = await call(`${BASE}/images/${fileKey3}?ids=${encodeURIComponent(chunk.join(","))}&format=png&scale=1`);
|
|
47244
|
-
Object.assign(merged, part.images);
|
|
47245
|
-
}
|
|
47246
|
-
return merged;
|
|
47247
|
-
}
|
|
47248
|
-
};
|
|
47249
|
-
}
|
|
47250
|
-
|
|
47251
47423
|
// packages/zaku/dist/lib/adapters/figma-variables-script.js
|
|
47252
47424
|
async function exportVariables(figma, options) {
|
|
47253
47425
|
const collections = [...await figma.variables.getLocalVariableCollectionsAsync()];
|
|
@@ -47952,9 +48124,9 @@ async function startPluginBridge(options = {}) {
|
|
|
47952
48124
|
if (!socket)
|
|
47953
48125
|
return Promise.resolve({ ok: false, error: `file ${fileKey3} is not open in Figma with the zaku plugin` });
|
|
47954
48126
|
const id2 = `c${++next}`;
|
|
47955
|
-
return new Promise((
|
|
48127
|
+
return new Promise((resolve4) => {
|
|
47956
48128
|
const timer = setTimeout(() => settle2(id2, { ok: false, error: `no answer from the zaku panel in ${timeoutMs / 1e3} s; ${PARTIAL}` }), timeoutMs);
|
|
47957
|
-
pending.set(id2, { socket, resolve:
|
|
48129
|
+
pending.set(id2, { socket, resolve: resolve4, timer });
|
|
47958
48130
|
send(socket, { ...message, id: id2 });
|
|
47959
48131
|
});
|
|
47960
48132
|
}
|
|
@@ -48273,6 +48445,71 @@ var copy = ({ config: config2, maps, outlines }) => {
|
|
|
48273
48445
|
return { findings };
|
|
48274
48446
|
};
|
|
48275
48447
|
|
|
48448
|
+
// packages/zaku/dist/lib/domain/file-labels.js
|
|
48449
|
+
var FAMILY_LABELS = {
|
|
48450
|
+
web: "Web",
|
|
48451
|
+
ios: "iOS",
|
|
48452
|
+
android: "Android",
|
|
48453
|
+
macos: "macOS",
|
|
48454
|
+
windows: "Windows",
|
|
48455
|
+
gnome: "Linux",
|
|
48456
|
+
kde: "Linux KDE"
|
|
48457
|
+
};
|
|
48458
|
+
var BRANCH_LABELS = { ui: "UI", native: "Native" };
|
|
48459
|
+
function branchLabel(branches) {
|
|
48460
|
+
const [only2] = branches;
|
|
48461
|
+
return branches.length === 1 && only2 ? BRANCH_LABELS[only2] : null;
|
|
48462
|
+
}
|
|
48463
|
+
function expectedFileName(product, role) {
|
|
48464
|
+
if (role.kind !== "library") {
|
|
48465
|
+
const family = `${product} - ${FAMILY_LABELS[role.family]}`;
|
|
48466
|
+
return role.kind === "prototype" ? `${family} Prototype` : family;
|
|
48467
|
+
}
|
|
48468
|
+
if (role.layer === "foundations")
|
|
48469
|
+
return null;
|
|
48470
|
+
const branch = branchLabel(role.branches);
|
|
48471
|
+
return branch ? `${product} - ${branch} Components` : `${product} - Components`;
|
|
48472
|
+
}
|
|
48473
|
+
function fileRoleLabel(role) {
|
|
48474
|
+
if (role.kind !== "library")
|
|
48475
|
+
return `${FAMILY_LABELS[role.family]} ${role.kind} file`;
|
|
48476
|
+
const branch = branchLabel(role.branches);
|
|
48477
|
+
return branch ? `${branch} ${role.layer} library` : `${role.layer} library`;
|
|
48478
|
+
}
|
|
48479
|
+
|
|
48480
|
+
// packages/zaku/dist/lib/domain/checks/file-names.js
|
|
48481
|
+
var fileNames = (input2) => {
|
|
48482
|
+
if (input2.fileNames === null)
|
|
48483
|
+
return { findings: [] };
|
|
48484
|
+
const graph = designGraph(input2.config);
|
|
48485
|
+
if (graph.legacy)
|
|
48486
|
+
return { findings: [] };
|
|
48487
|
+
const roles = [
|
|
48488
|
+
...graph.products.map((file2) => [file2.key, { kind: "product", family: file2.family }]),
|
|
48489
|
+
...graph.prototypes.map((file2) => [file2.key, { kind: "prototype", family: file2.family }]),
|
|
48490
|
+
...graph.libraries.map((file2) => [
|
|
48491
|
+
file2.key,
|
|
48492
|
+
{ kind: "library", layer: file2.layer, branches: file2.branches }
|
|
48493
|
+
])
|
|
48494
|
+
];
|
|
48495
|
+
const names = new Map(input2.fileNames.map((file2) => [file2.key, file2.name]));
|
|
48496
|
+
const { product } = input2.config;
|
|
48497
|
+
const findings = [];
|
|
48498
|
+
for (const [key, role] of roles) {
|
|
48499
|
+
const actual = names.get(key);
|
|
48500
|
+
const expected = expectedFileName(product, role);
|
|
48501
|
+
if (actual === void 0 || expected === null || actual === expected)
|
|
48502
|
+
continue;
|
|
48503
|
+
const label2 = fileRoleLabel(role);
|
|
48504
|
+
const article = /^(iOS|Android) /.test(label2) ? "an" : "a";
|
|
48505
|
+
findings.push({
|
|
48506
|
+
check: "file-names",
|
|
48507
|
+
message: `${key} is named ${actual}; ${article} ${label2} of ${product} is named ${expected}; rename it in Figma, then run zaku outline`
|
|
48508
|
+
});
|
|
48509
|
+
}
|
|
48510
|
+
return { findings };
|
|
48511
|
+
};
|
|
48512
|
+
|
|
48276
48513
|
// packages/zaku/dist/lib/domain/checks/coverage.js
|
|
48277
48514
|
function frameKey(feature, name) {
|
|
48278
48515
|
return `${feature}
|
|
@@ -48482,8 +48719,8 @@ var component = ({ config: config2, outlines, productComponents }) => {
|
|
|
48482
48719
|
const findings = [];
|
|
48483
48720
|
const graph = designGraph(config2);
|
|
48484
48721
|
for (const drawn of productComponents) {
|
|
48485
|
-
const
|
|
48486
|
-
const branches = new Set(
|
|
48722
|
+
const families2 = graph.products.filter((product) => product.key === drawn.source).map((product) => product.family);
|
|
48723
|
+
const branches = new Set(families2.flatMap((family) => graph.targetsOf(family)).flatMap((target) => graph.branchOf(target) ?? []));
|
|
48487
48724
|
const homes = graph.libraries.filter((library) => library.layer === "components" && library.branches.some((branch) => branches.has(branch))).map((library) => library.key);
|
|
48488
48725
|
findings.push({
|
|
48489
48726
|
check: "component",
|
|
@@ -49470,6 +49707,7 @@ var ALL_CHECKS = {
|
|
|
49470
49707
|
"system-bars": systemBars,
|
|
49471
49708
|
placement,
|
|
49472
49709
|
naming,
|
|
49710
|
+
"file-names": fileNames,
|
|
49473
49711
|
component,
|
|
49474
49712
|
prototype
|
|
49475
49713
|
};
|
|
@@ -49510,6 +49748,7 @@ var CHECK_IDS = [
|
|
|
49510
49748
|
"empty",
|
|
49511
49749
|
"documentation",
|
|
49512
49750
|
"naming",
|
|
49751
|
+
"file-names",
|
|
49513
49752
|
"component",
|
|
49514
49753
|
"prototype"
|
|
49515
49754
|
];
|
|
@@ -49627,17 +49866,10 @@ async function optional3(read, findings) {
|
|
|
49627
49866
|
throw error62;
|
|
49628
49867
|
}
|
|
49629
49868
|
}
|
|
49630
|
-
async function loadDesign(
|
|
49631
|
-
const paths = designPaths(root);
|
|
49869
|
+
async function loadDesign(product) {
|
|
49870
|
+
const paths = designPaths(product.root);
|
|
49632
49871
|
const findings = [];
|
|
49633
|
-
|
|
49634
|
-
try {
|
|
49635
|
-
config2 = await readDesignFile(paths.config, zakuConfigSchema);
|
|
49636
|
-
} catch (error62) {
|
|
49637
|
-
if (error62 instanceof DesignFileInvalid)
|
|
49638
|
-
return { input: null, findings: [schemaFinding(error62)] };
|
|
49639
|
-
throw error62;
|
|
49640
|
-
}
|
|
49872
|
+
const { config: config2 } = product;
|
|
49641
49873
|
const { maps, errors: mapErrors } = await loadMaps(paths.maps);
|
|
49642
49874
|
findings.push(...mapErrors.map(schemaFinding));
|
|
49643
49875
|
for (const key of indexTitles(maps).duplicates) {
|
|
@@ -49648,7 +49880,7 @@ async function loadDesign(root) {
|
|
|
49648
49880
|
message: `two screens share the title ${title}; a frame name could not tell them apart`
|
|
49649
49881
|
});
|
|
49650
49882
|
}
|
|
49651
|
-
const { outlines, flows, unmapped, errors: outlineErrors } = await loadOutlines(paths.outline);
|
|
49883
|
+
const { outlines, flows, unmapped, files: files2, errors: outlineErrors } = await loadOutlines(paths.outline);
|
|
49652
49884
|
findings.push(...outlineErrors.map(schemaFinding));
|
|
49653
49885
|
const { libraries, kits, errors: snapshotErrors } = await readDesignSnapshots(paths, config2);
|
|
49654
49886
|
findings.push(...snapshotErrors.map(schemaFinding));
|
|
@@ -49665,15 +49897,80 @@ async function loadDesign(root) {
|
|
|
49665
49897
|
libraries,
|
|
49666
49898
|
kits,
|
|
49667
49899
|
tokens,
|
|
49668
|
-
recipe: recipe2
|
|
49900
|
+
recipe: recipe2,
|
|
49901
|
+
fileNames: files2?.files ?? null
|
|
49669
49902
|
},
|
|
49670
49903
|
findings
|
|
49671
49904
|
};
|
|
49672
49905
|
}
|
|
49673
49906
|
|
|
49907
|
+
// packages/zaku/dist/lib/repositories/workspace.js
|
|
49908
|
+
import { readFile as readFile6 } from "node:fs/promises";
|
|
49909
|
+
import { dirname as dirname4, join as join9, resolve as resolve2 } from "node:path";
|
|
49910
|
+
var WORKSPACE_CONFIG = "zaku.config.yaml";
|
|
49911
|
+
async function readOptionalText(path2) {
|
|
49912
|
+
try {
|
|
49913
|
+
return await readFile6(path2, "utf8");
|
|
49914
|
+
} catch (error62) {
|
|
49915
|
+
if (error62.code === "ENOENT")
|
|
49916
|
+
return null;
|
|
49917
|
+
throw error62;
|
|
49918
|
+
}
|
|
49919
|
+
}
|
|
49920
|
+
function only(products, name) {
|
|
49921
|
+
if (name === void 0)
|
|
49922
|
+
return products;
|
|
49923
|
+
const named = products.filter((product) => product.name === name);
|
|
49924
|
+
if (named.length === 0)
|
|
49925
|
+
throw new ProductUnknown(name, products.map((product) => product.name));
|
|
49926
|
+
return named;
|
|
49927
|
+
}
|
|
49928
|
+
async function readWorkspace(cwd, options) {
|
|
49929
|
+
const configPath = resolve2(cwd, options.config ?? WORKSPACE_CONFIG);
|
|
49930
|
+
const text = await readOptionalText(configPath);
|
|
49931
|
+
if (text === null) {
|
|
49932
|
+
if (options.config !== void 0)
|
|
49933
|
+
throw new WorkspaceConfigMissing(configPath, null);
|
|
49934
|
+
const root = resolve2(cwd, "docs", "design");
|
|
49935
|
+
const legacyPath = designPaths(root).config;
|
|
49936
|
+
const config2 = await readOptionalDesignFile(legacyPath, zakuConfigSchema);
|
|
49937
|
+
if (config2 === null)
|
|
49938
|
+
throw new WorkspaceConfigMissing(configPath, legacyPath);
|
|
49939
|
+
const products2 = only([{ name: config2.product, root, config: config2 }], options.product);
|
|
49940
|
+
return { configPath: null, dir: resolve2(cwd), products: products2, legacy: true, budget: config2.budget };
|
|
49941
|
+
}
|
|
49942
|
+
const dir = dirname4(configPath);
|
|
49943
|
+
const workspace = parseDesignFile(configPath, text, workspaceConfigSchema);
|
|
49944
|
+
if (workspace.products === void 0) {
|
|
49945
|
+
const config2 = parseDesignFile(configPath, text, zakuConfigSchema);
|
|
49946
|
+
const products2 = only([{ name: config2.product, root: join9(dir, "design"), config: config2 }], options.product);
|
|
49947
|
+
return { configPath, dir, products: products2, legacy: false, budget: config2.budget };
|
|
49948
|
+
}
|
|
49949
|
+
const listed = workspace.products.map((product) => ({ name: product.name, root: resolve2(dir, product.root) }));
|
|
49950
|
+
const products = [];
|
|
49951
|
+
for (const { name, root } of only(listed, options.product)) {
|
|
49952
|
+
const path2 = designPaths(root).config;
|
|
49953
|
+
try {
|
|
49954
|
+
const own2 = await readOptionalDesignFile(path2, external_exports.unknown());
|
|
49955
|
+
if (own2 === null)
|
|
49956
|
+
throw new ProductConfigMissing(path2, name);
|
|
49957
|
+
products.push({ name, root, config: mergeProductConfig(workspace, name, own2) });
|
|
49958
|
+
} catch (error62) {
|
|
49959
|
+
if (error62 instanceof ProductConfigMissing)
|
|
49960
|
+
products.push({ name, root, refusal: error62 });
|
|
49961
|
+
else if (error62 instanceof DesignFileInvalid) {
|
|
49962
|
+
const refusal = error62.path === path2 ? error62 : new DesignFileInvalid(path2, error62.issues);
|
|
49963
|
+
products.push({ name, root, refusal });
|
|
49964
|
+
} else
|
|
49965
|
+
throw error62;
|
|
49966
|
+
}
|
|
49967
|
+
}
|
|
49968
|
+
return { configPath, dir, products, legacy: false, budget: workspace.budget ?? budgetSchema.parse({}) };
|
|
49969
|
+
}
|
|
49970
|
+
|
|
49674
49971
|
// apps/zaku-cli/src/dependencies.ts
|
|
49675
49972
|
function compose(seams) {
|
|
49676
|
-
const scope =
|
|
49973
|
+
const scope = import_tsyringe11.container.createChildContainer();
|
|
49677
49974
|
scope.register(TOKENS.CLOCK, { useValue: { now: seams.now } });
|
|
49678
49975
|
scope.register(TOKENS.RUN_COMMAND, { useValue: seams.run });
|
|
49679
49976
|
scope.register(TOKENS.BUDGET_LEDGER, {
|
|
@@ -49702,6 +49999,9 @@ function refusalOf(error62) {
|
|
|
49702
49999
|
if (error62 instanceof FigmaFileKeyMissing) return { code: 3, line: error62.message };
|
|
49703
50000
|
if (error62 instanceof FigmaTokenMissing) return { code: 3, line: error62.message };
|
|
49704
50001
|
if (error62 instanceof LibraryKeyMissing) return { code: 3, line: error62.message };
|
|
50002
|
+
if (error62 instanceof WorkspaceConfigMissing) return { code: 3, line: error62.message };
|
|
50003
|
+
if (error62 instanceof ProductConfigMissing) return { code: 3, line: error62.message };
|
|
50004
|
+
if (error62 instanceof ProductUnknown || error62 instanceof ProductRequired) return { code: 3, line: error62.message };
|
|
49705
50005
|
if (error62 instanceof RecipePageFailed) return { code: 2, line: `zaku recipe: ${error62.message}` };
|
|
49706
50006
|
return null;
|
|
49707
50007
|
}
|
|
@@ -57211,7 +57511,7 @@ var Protocol = class {
|
|
|
57211
57511
|
return;
|
|
57212
57512
|
}
|
|
57213
57513
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
57214
|
-
await new Promise((
|
|
57514
|
+
await new Promise((resolve4) => setTimeout(resolve4, pollInterval));
|
|
57215
57515
|
options?.signal?.throwIfAborted();
|
|
57216
57516
|
}
|
|
57217
57517
|
} catch (error62) {
|
|
@@ -57228,7 +57528,7 @@ var Protocol = class {
|
|
|
57228
57528
|
*/
|
|
57229
57529
|
request(request, resultSchema, options) {
|
|
57230
57530
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
57231
|
-
return new Promise((
|
|
57531
|
+
return new Promise((resolve4, reject) => {
|
|
57232
57532
|
const earlyReject = (error62) => {
|
|
57233
57533
|
reject(error62);
|
|
57234
57534
|
};
|
|
@@ -57306,7 +57606,7 @@ var Protocol = class {
|
|
|
57306
57606
|
if (!parseResult.success) {
|
|
57307
57607
|
reject(parseResult.error);
|
|
57308
57608
|
} else {
|
|
57309
|
-
|
|
57609
|
+
resolve4(parseResult.data);
|
|
57310
57610
|
}
|
|
57311
57611
|
} catch (error62) {
|
|
57312
57612
|
reject(error62);
|
|
@@ -57568,12 +57868,12 @@ var Protocol = class {
|
|
|
57568
57868
|
}
|
|
57569
57869
|
} catch {
|
|
57570
57870
|
}
|
|
57571
|
-
return new Promise((
|
|
57871
|
+
return new Promise((resolve4, reject) => {
|
|
57572
57872
|
if (signal.aborted) {
|
|
57573
57873
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
57574
57874
|
return;
|
|
57575
57875
|
}
|
|
57576
|
-
const timeoutId = setTimeout(
|
|
57876
|
+
const timeoutId = setTimeout(resolve4, interval);
|
|
57577
57877
|
signal.addEventListener("abort", () => {
|
|
57578
57878
|
clearTimeout(timeoutId);
|
|
57579
57879
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -58713,7 +59013,7 @@ var McpServer = class {
|
|
|
58713
59013
|
let task = createTaskResult.task;
|
|
58714
59014
|
const pollInterval = task.pollInterval ?? 5e3;
|
|
58715
59015
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
58716
|
-
await new Promise((
|
|
59016
|
+
await new Promise((resolve4) => setTimeout(resolve4, pollInterval));
|
|
58717
59017
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
58718
59018
|
if (!updatedTask) {
|
|
58719
59019
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -59377,12 +59677,12 @@ var StdioServerTransport = class {
|
|
|
59377
59677
|
this.onclose?.();
|
|
59378
59678
|
}
|
|
59379
59679
|
send(message) {
|
|
59380
|
-
return new Promise((
|
|
59680
|
+
return new Promise((resolve4) => {
|
|
59381
59681
|
const json2 = serializeMessage(message);
|
|
59382
59682
|
if (this._stdout.write(json2)) {
|
|
59383
|
-
|
|
59683
|
+
resolve4();
|
|
59384
59684
|
} else {
|
|
59385
|
-
this._stdout.once("drain",
|
|
59685
|
+
this._stdout.once("drain", resolve4);
|
|
59386
59686
|
}
|
|
59387
59687
|
});
|
|
59388
59688
|
}
|
|
@@ -59391,11 +59691,11 @@ var StdioServerTransport = class {
|
|
|
59391
59691
|
// apps/zaku-cli/src/mcp/server.ts
|
|
59392
59692
|
import { mkdir as mkdir5 } from "node:fs/promises";
|
|
59393
59693
|
import { tmpdir } from "node:os";
|
|
59394
|
-
import { join as
|
|
59694
|
+
import { join as join12 } from "node:path";
|
|
59395
59695
|
|
|
59396
59696
|
// apps/zaku-cli/src/mcp/screenshots.ts
|
|
59397
59697
|
import { readdir as readdir4, rm as rm3, stat } from "node:fs/promises";
|
|
59398
|
-
import { join as
|
|
59698
|
+
import { join as join10 } from "node:path";
|
|
59399
59699
|
var KEPT_MS = 24 * 60 * 60 * 1e3;
|
|
59400
59700
|
async function pruneScreenshots(dir, now) {
|
|
59401
59701
|
let names;
|
|
@@ -59405,7 +59705,7 @@ async function pruneScreenshots(dir, now) {
|
|
|
59405
59705
|
return;
|
|
59406
59706
|
}
|
|
59407
59707
|
for (const name of names.filter((entry) => entry.endsWith(".png"))) {
|
|
59408
|
-
const path2 =
|
|
59708
|
+
const path2 = join10(dir, name);
|
|
59409
59709
|
const written = await stat(path2).then(
|
|
59410
59710
|
(stats) => stats.mtimeMs,
|
|
59411
59711
|
() => now
|
|
@@ -59416,7 +59716,7 @@ async function pruneScreenshots(dir, now) {
|
|
|
59416
59716
|
|
|
59417
59717
|
// apps/zaku-cli/src/mcp/tools.ts
|
|
59418
59718
|
import { writeFile as writeFile5 } from "node:fs/promises";
|
|
59419
|
-
import { join as
|
|
59719
|
+
import { join as join11 } from "node:path";
|
|
59420
59720
|
var fileKey2 = external_exports.string().min(1).regex(/^[0-9a-zA-Z]{22,128}$/).describe(
|
|
59421
59721
|
"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."
|
|
59422
59722
|
);
|
|
@@ -59460,7 +59760,7 @@ function registerFigmaTools(server, bridge, options) {
|
|
|
59460
59760
|
options.timeoutMs
|
|
59461
59761
|
);
|
|
59462
59762
|
if (!answer.ok) return { isError: true, content: [{ type: "text", text: answer.error }] };
|
|
59463
|
-
const path2 =
|
|
59763
|
+
const path2 = join11(options.imageDir, `${id2.replace(":", "-")}-${Date.now()}.png`);
|
|
59464
59764
|
await writeFile5(path2, Buffer.from(answer.png, "base64"));
|
|
59465
59765
|
const text = JSON.stringify({
|
|
59466
59766
|
path: path2,
|
|
@@ -59486,7 +59786,7 @@ async function serveMcp(log) {
|
|
|
59486
59786
|
log(
|
|
59487
59787
|
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}`
|
|
59488
59788
|
);
|
|
59489
|
-
const imageDir =
|
|
59789
|
+
const imageDir = join12(tmpdir(), "zaku-screenshots");
|
|
59490
59790
|
await mkdir5(imageDir, { recursive: true });
|
|
59491
59791
|
await pruneScreenshots(imageDir, Date.now());
|
|
59492
59792
|
const server = new McpServer({ name: "zaku", version: "1" });
|
|
@@ -59503,59 +59803,175 @@ async function serveMcp(log) {
|
|
|
59503
59803
|
|
|
59504
59804
|
// apps/zaku-cli/src/cli.ts
|
|
59505
59805
|
var USE_FIGMA_CODE_LIMIT = 5e4;
|
|
59506
|
-
var USAGE = "usage: zaku <check|outline|tokens|recipe|library|libraries|rules|budget|schema|mcp> [--
|
|
59507
|
-
|
|
59508
|
-
try {
|
|
59509
|
-
return await cli.bus.send(command);
|
|
59510
|
-
} catch (error62) {
|
|
59511
|
-
const refusal = refusalOf(error62);
|
|
59512
|
-
if (!refusal) throw error62;
|
|
59513
|
-
io.err(refusal.line);
|
|
59514
|
-
finish(refusal.code);
|
|
59515
|
-
return null;
|
|
59516
|
-
}
|
|
59517
|
-
}
|
|
59806
|
+
var USAGE = "usage: zaku <check|outline|tokens|recipe|library|libraries|products|rules|budget|schema|mcp> [--config zaku.config.yaml] [--product <name>]";
|
|
59807
|
+
var LEGACY_WARNING = "zaku: read docs/design/zaku.yaml; move it to zaku.config.yaml at the repository root and the design to design/";
|
|
59518
59808
|
async function recordRestCalls(cli, io) {
|
|
59519
59809
|
const count = cli.restCalls();
|
|
59520
59810
|
if (count === 0) return;
|
|
59521
59811
|
const { seat, run } = seatAndRun(io.env);
|
|
59522
59812
|
await cli.bus.send(new RecordBudgetCalls({ day: today(clock.now()), seat, run, kind: "rest", count }));
|
|
59523
59813
|
}
|
|
59814
|
+
var CONFIG_OPTION = ["--config <path>", "the workspace config, when it is not zaku.config.yaml here"];
|
|
59815
|
+
var PRODUCT_OPTION = ["--product <name>", "only this product, by the name the workspace config gives it"];
|
|
59816
|
+
function warnLegacy(io, workspace) {
|
|
59817
|
+
if (workspace.legacy) io.err(LEGACY_WARNING);
|
|
59818
|
+
}
|
|
59819
|
+
async function workspaceOf(io, options) {
|
|
59820
|
+
const workspace = await readWorkspace(io.cwd, options);
|
|
59821
|
+
warnLegacy(io, workspace);
|
|
59822
|
+
return workspace;
|
|
59823
|
+
}
|
|
59824
|
+
function oneProduct(workspace, command) {
|
|
59825
|
+
const [product, ...rest] = workspace.products;
|
|
59826
|
+
if (product === void 0 || rest.length > 0) {
|
|
59827
|
+
throw new ProductRequired(
|
|
59828
|
+
command,
|
|
59829
|
+
workspace.products.map((each) => each.name)
|
|
59830
|
+
);
|
|
59831
|
+
}
|
|
59832
|
+
if ("refusal" in product) throw product.refusal;
|
|
59833
|
+
return product;
|
|
59834
|
+
}
|
|
59835
|
+
function onlyWithOne(workspace, command, option, given) {
|
|
59836
|
+
if (given !== void 0 && workspace.products.length > 1) {
|
|
59837
|
+
throw new ProductRequired(
|
|
59838
|
+
`${command} ${option}`,
|
|
59839
|
+
workspace.products.map((product) => product.name)
|
|
59840
|
+
);
|
|
59841
|
+
}
|
|
59842
|
+
}
|
|
59843
|
+
function productFailure(error62) {
|
|
59844
|
+
const refusal = refusalOf(error62);
|
|
59845
|
+
if (refusal) return refusal;
|
|
59846
|
+
if (error62 instanceof DesignFileInvalid || error62 instanceof FigmaRequestFailed) {
|
|
59847
|
+
return { code: 1, line: `zaku: ${error62.message}` };
|
|
59848
|
+
}
|
|
59849
|
+
throw error62;
|
|
59850
|
+
}
|
|
59851
|
+
function reportRefusal(io, error62) {
|
|
59852
|
+
const failure2 = productFailure(error62);
|
|
59853
|
+
io.err(failure2.line);
|
|
59854
|
+
return failure2.code;
|
|
59855
|
+
}
|
|
59856
|
+
async function forEachProduct(io, workspace, run) {
|
|
59857
|
+
let code = 0;
|
|
59858
|
+
for (const product of workspace.products) {
|
|
59859
|
+
if (workspace.products.length > 1) io.out(`== ${product.name}`);
|
|
59860
|
+
let exit;
|
|
59861
|
+
try {
|
|
59862
|
+
if ("refusal" in product) throw product.refusal;
|
|
59863
|
+
exit = await run(product);
|
|
59864
|
+
} catch (error62) {
|
|
59865
|
+
exit = reportRefusal(io, error62);
|
|
59866
|
+
}
|
|
59867
|
+
code = Math.max(code, exit);
|
|
59868
|
+
}
|
|
59869
|
+
return code;
|
|
59870
|
+
}
|
|
59524
59871
|
var librariesCommand = (program2, io, finish) => {
|
|
59525
|
-
program2.command("libraries").description("print the design graph: what each target draws from, and what each file extends and is extended by").option(
|
|
59526
|
-
const
|
|
59527
|
-
|
|
59528
|
-
|
|
59872
|
+
program2.command("libraries").description("print the design graph: what each target draws from, and what each file extends and is extended by").option(...CONFIG_OPTION).option(...PRODUCT_OPTION).action(async (options) => {
|
|
59873
|
+
const workspace = await workspaceOf(io, options);
|
|
59874
|
+
finish(
|
|
59875
|
+
await forEachProduct(io, workspace, async ({ root, config: config2 }) => {
|
|
59876
|
+
for (const line of printGraph(config2, await readDesignSnapshots(designPaths(root), config2))) io.out(line);
|
|
59877
|
+
return 0;
|
|
59878
|
+
})
|
|
59879
|
+
);
|
|
59880
|
+
});
|
|
59881
|
+
};
|
|
59882
|
+
var productsCommand = (program2, io, finish) => {
|
|
59883
|
+
program2.command("products").description("print each product the workspace config lists, with its design directory").option(...CONFIG_OPTION).option("--json", "print them as JSON").action(async (options) => {
|
|
59884
|
+
const workspace = await workspaceOf(io, options.config === void 0 ? {} : { config: options.config });
|
|
59885
|
+
const rows = workspace.products.map((product) => ({
|
|
59886
|
+
name: product.name,
|
|
59887
|
+
root: relative3(io.cwd, product.root) || "."
|
|
59888
|
+
}));
|
|
59889
|
+
if (options.json) io.out(JSON.stringify(rows, null, 2));
|
|
59890
|
+
else for (const row of rows) io.out(`${row.name} ${row.root}`);
|
|
59529
59891
|
finish(0);
|
|
59530
59892
|
});
|
|
59531
59893
|
};
|
|
59532
59894
|
var schemaCommand = (program2, io, finish, cli) => {
|
|
59533
|
-
program2.command("schema").description("write the JSON Schemas an editor reads for the design files").option("--out <dir>", "where to write them
|
|
59534
|
-
const
|
|
59895
|
+
program2.command("schema").description("write the JSON Schemas an editor reads for the design files").option("--out <dir>", "where to write them; the workspace config's directory when left out").option(...CONFIG_OPTION).action(async (options) => {
|
|
59896
|
+
const out = options.out !== void 0 ? resolve3(io.cwd, options.out) : options.config !== void 0 ? dirname5(resolve3(io.cwd, options.config)) : resolve3(io.cwd);
|
|
59897
|
+
const written = await cli.bus.send(new WriteSchemas({ out }));
|
|
59535
59898
|
for (const path2 of written) io.out(`wrote ${path2}`);
|
|
59536
59899
|
finish(0);
|
|
59537
59900
|
});
|
|
59538
59901
|
};
|
|
59902
|
+
function checkExit(codes) {
|
|
59903
|
+
const rank = (code) => code === 1 ? 2 : code === 2 ? 1 : code;
|
|
59904
|
+
return codes.reduce((worst, code) => rank(code) > rank(worst) ? code : worst, 0);
|
|
59905
|
+
}
|
|
59906
|
+
async function checkProduct(product, ran) {
|
|
59907
|
+
let loaded;
|
|
59908
|
+
if ("refusal" in product) {
|
|
59909
|
+
if (!(product.refusal instanceof DesignFileInvalid)) return { refusal: product.refusal };
|
|
59910
|
+
loaded = { input: null, findings: [{ check: "schema", message: product.refusal.message }] };
|
|
59911
|
+
} else {
|
|
59912
|
+
try {
|
|
59913
|
+
loaded = await loadDesign(product);
|
|
59914
|
+
} catch (error62) {
|
|
59915
|
+
if (!(error62 instanceof DesignFileInvalid)) throw error62;
|
|
59916
|
+
loaded = { input: null, findings: [{ check: "schema", message: error62.message }] };
|
|
59917
|
+
}
|
|
59918
|
+
}
|
|
59919
|
+
const report = loaded.input ? runChecks(loaded.input, ALL_CHECKS) : { findings: [], notRun: [], passed: [] };
|
|
59920
|
+
report.findings.unshift(...loaded.findings);
|
|
59921
|
+
if (ran) report.findings.push(...ran.findings);
|
|
59922
|
+
const left = ran ? leftOut(ran) : [];
|
|
59923
|
+
return {
|
|
59924
|
+
report: { ...report, ...left.length > 0 ? { leftOut: left } : {} },
|
|
59925
|
+
code: loaded.input ? exitCode(report) : 1
|
|
59926
|
+
};
|
|
59927
|
+
}
|
|
59539
59928
|
var checkCommand = (program2, io, finish) => {
|
|
59540
|
-
program2.command("check").description("run every check over
|
|
59541
|
-
|
|
59542
|
-
|
|
59543
|
-
|
|
59544
|
-
|
|
59545
|
-
|
|
59546
|
-
|
|
59929
|
+
program2.command("check").description("run every check over each product's committed design files").option(...CONFIG_OPTION).option(...PRODUCT_OPTION).option("--json", "print the report as JSON, keyed by product when there are several").option("--input <rules.json>", "what use_figma returned for zaku rules script, with or without --after").action(async (options) => {
|
|
59930
|
+
let workspace;
|
|
59931
|
+
try {
|
|
59932
|
+
workspace = await workspaceOf(io, options);
|
|
59933
|
+
} catch (error62) {
|
|
59934
|
+
if (!(error62 instanceof DesignFileInvalid)) throw error62;
|
|
59935
|
+
const report = { findings: [{ check: "schema", message: error62.message }], notRun: [], passed: [] };
|
|
59936
|
+
if (options.json) io.out(JSON.stringify(report, null, 2));
|
|
59937
|
+
else for (const line of formatReport(report)) io.out(line);
|
|
59938
|
+
finish(1);
|
|
59939
|
+
return;
|
|
59940
|
+
}
|
|
59941
|
+
onlyWithOne(workspace, "zaku check", "--input", options.input);
|
|
59942
|
+
const answer = options.input ? parseDesignFile(options.input, await readFile7(resolve3(io.cwd, options.input), "utf8"), rulesAnswerSchema) : null;
|
|
59943
|
+
if (answer && "rulesError" in answer) {
|
|
59944
|
+
io.err(`zaku check: the rules did not run after the write: ${answer.rulesError}`);
|
|
59547
59945
|
finish(1);
|
|
59548
59946
|
return;
|
|
59549
59947
|
}
|
|
59550
|
-
|
|
59551
|
-
const
|
|
59552
|
-
|
|
59553
|
-
|
|
59554
|
-
|
|
59948
|
+
const several = workspace.products.length > 1;
|
|
59949
|
+
const reports = {};
|
|
59950
|
+
const codes = [];
|
|
59951
|
+
for (const product of workspace.products) {
|
|
59952
|
+
if (several && !options.json) io.out(`== ${product.name}`);
|
|
59953
|
+
const checked = await checkProduct(product, answer);
|
|
59954
|
+
if ("refusal" in checked) {
|
|
59955
|
+
const failure2 = productFailure(checked.refusal);
|
|
59956
|
+
io.err(failure2.line);
|
|
59957
|
+
codes.push(failure2.code);
|
|
59958
|
+
if (options.json) reports[product.name] = { refusal: failure2.line };
|
|
59959
|
+
continue;
|
|
59960
|
+
}
|
|
59961
|
+
codes.push(checked.code);
|
|
59962
|
+
if (options.json) reports[product.name] = checked.report;
|
|
59963
|
+
else for (const line of [...checked.report.leftOut ?? [], ...formatReport(checked.report)]) io.out(line);
|
|
59964
|
+
}
|
|
59965
|
+
if (options.json) {
|
|
59966
|
+
const [only2] = Object.values(reports);
|
|
59967
|
+
if (several) io.out(JSON.stringify(reports, null, 2));
|
|
59968
|
+
else if (only2) io.out(JSON.stringify(only2, null, 2));
|
|
59969
|
+
}
|
|
59970
|
+
finish(checkExit(codes));
|
|
59555
59971
|
});
|
|
59556
59972
|
};
|
|
59557
59973
|
async function productPlaywright(cwd) {
|
|
59558
|
-
const require2 = createRequire(
|
|
59974
|
+
const require2 = createRequire(join13(cwd, "package.json"));
|
|
59559
59975
|
let resolved;
|
|
59560
59976
|
try {
|
|
59561
59977
|
resolved = require2.resolve("playwright");
|
|
@@ -59566,15 +59982,15 @@ async function productPlaywright(cwd) {
|
|
|
59566
59982
|
return require2("playwright");
|
|
59567
59983
|
}
|
|
59568
59984
|
function fromProductTree(cwd, resolved) {
|
|
59569
|
-
for (let dir =
|
|
59570
|
-
if (resolved.startsWith(
|
|
59571
|
-
if (
|
|
59985
|
+
for (let dir = resolve3(cwd); ; dir = dirname5(dir)) {
|
|
59986
|
+
if (resolved.startsWith(join13(dir, "node_modules") + sep)) return true;
|
|
59987
|
+
if (dirname5(dir) === dir) return false;
|
|
59572
59988
|
}
|
|
59573
59989
|
}
|
|
59574
59990
|
var runners = {
|
|
59575
59991
|
run: execRun,
|
|
59576
59992
|
loadPlaywright: productPlaywright,
|
|
59577
|
-
rulesLibrary: () =>
|
|
59993
|
+
rulesLibrary: () => readFile7(fileURLToPath(new URL("./rules.js", import.meta.url)), "utf8")
|
|
59578
59994
|
};
|
|
59579
59995
|
var mcpCommand = (program2, io, finish) => {
|
|
59580
59996
|
program2.command("mcp").description(
|
|
@@ -59585,30 +60001,35 @@ var mcpCommand = (program2, io, finish) => {
|
|
|
59585
60001
|
});
|
|
59586
60002
|
};
|
|
59587
60003
|
var tokensCommand = (program2, io, finish, cli) => {
|
|
59588
|
-
program2.command("tokens").description("write the code's tokens to tokens.json, from the design system zaku.yaml names").option("--css <path>", "the stylesheet that declares :root and .dark (shadcn)").option(
|
|
59589
|
-
const
|
|
59590
|
-
|
|
59591
|
-
|
|
59592
|
-
|
|
59593
|
-
|
|
59594
|
-
|
|
59595
|
-
|
|
59596
|
-
|
|
59597
|
-
|
|
60004
|
+
program2.command("tokens").description("write the code's tokens to tokens.json, from the design system zaku.yaml names").option("--css <path>", "the stylesheet that declares :root and .dark (shadcn), over designSystem.shadcn.css").option(...CONFIG_OPTION).option(...PRODUCT_OPTION).action(async (options) => {
|
|
60005
|
+
const workspace = await workspaceOf(io, options);
|
|
60006
|
+
onlyWithOne(workspace, "zaku tokens", "--css", options.css);
|
|
60007
|
+
finish(
|
|
60008
|
+
await forEachProduct(io, workspace, async ({ root, config: config2 }) => {
|
|
60009
|
+
const named = "shadcn" in config2.designSystem ? config2.designSystem.shadcn.css : void 0;
|
|
60010
|
+
const css = options.css ? resolve3(io.cwd, options.css) : named !== void 0 ? resolve3(workspace.dir, named) : null;
|
|
60011
|
+
const command = new WriteTokens({ root, config: config2, cwd: workspace.dir, css });
|
|
60012
|
+
const written = await cli.bus.send(command);
|
|
60013
|
+
io.out(`wrote ${written.path}: ${written.colours} colours, ${written.from}`);
|
|
60014
|
+
return 0;
|
|
60015
|
+
})
|
|
60016
|
+
);
|
|
59598
60017
|
});
|
|
59599
60018
|
};
|
|
59600
60019
|
var recipeCommand = (program2, io, finish, cli) => {
|
|
59601
|
-
program2.command("recipe").description("write what the code computes for every variant to recipe.json, from the product's recipe page").option("--url <url>", "the recipe page, when it is not zaku.yaml's recipe.url").option(
|
|
59602
|
-
const
|
|
59603
|
-
|
|
59604
|
-
|
|
59605
|
-
|
|
59606
|
-
|
|
59607
|
-
|
|
59608
|
-
|
|
59609
|
-
|
|
60020
|
+
program2.command("recipe").description("write what the code computes for every variant to recipe.json, from the product's recipe page").option("--url <url>", "the recipe page, when it is not zaku.yaml's recipe.url").option(...CONFIG_OPTION).option(...PRODUCT_OPTION).action(async (options) => {
|
|
60021
|
+
const workspace = await workspaceOf(io, options);
|
|
60022
|
+
onlyWithOne(workspace, "zaku recipe", "--url", options.url);
|
|
60023
|
+
finish(
|
|
60024
|
+
await forEachProduct(io, workspace, async ({ root, config: config2 }) => {
|
|
60025
|
+
const command = new WriteRecipe({ root, config: config2, url: options.url ?? null });
|
|
60026
|
+
const written = await cli.bus.send(command);
|
|
60027
|
+
io.out(
|
|
60028
|
+
`wrote ${written.path}: ${written.components} components, ${written.variants} variants, in light and dark`
|
|
60029
|
+
);
|
|
60030
|
+
return 0;
|
|
60031
|
+
})
|
|
59610
60032
|
);
|
|
59611
|
-
finish(0);
|
|
59612
60033
|
});
|
|
59613
60034
|
};
|
|
59614
60035
|
var clock = { now: () => /* @__PURE__ */ new Date() };
|
|
@@ -59629,10 +60050,21 @@ var budgetCommand = (program2, io, finish, cli) => {
|
|
|
59629
60050
|
await cli.bus.send(new RecordBudgetCalls({ day, seat, run, kind: options.kind, count: options.count }));
|
|
59630
60051
|
finish(0);
|
|
59631
60052
|
});
|
|
59632
|
-
budget.command("status").description("exit 4 when the budget refuses another MCP call").option(
|
|
60053
|
+
budget.command("status").description("exit 4 when the budget refuses another MCP call").option(...CONFIG_OPTION).action(async (options) => {
|
|
59633
60054
|
const { path: path2, seat, run, day } = ledger();
|
|
59634
|
-
|
|
59635
|
-
|
|
60055
|
+
let budgets;
|
|
60056
|
+
try {
|
|
60057
|
+
const workspace = await workspaceOf(io, options.config === void 0 ? {} : { config: options.config });
|
|
60058
|
+
budgets = workspace.products.map(
|
|
60059
|
+
(product) => "refusal" in product ? workspace.budget : product.config.budget
|
|
60060
|
+
);
|
|
60061
|
+
} catch (error62) {
|
|
60062
|
+
if (!(error62 instanceof WorkspaceConfigMissing) || options.config !== void 0) throw error62;
|
|
60063
|
+
budgets = [budgetSchema.parse({})];
|
|
60064
|
+
}
|
|
60065
|
+
const read = await readLedger(path2, day);
|
|
60066
|
+
const allowances = budgets.map((budget2) => mcpAllowance(read, seat, run, budget2));
|
|
60067
|
+
const allowance = allowances.reduce((chosen, each) => chosen.ok && !each.ok ? each : chosen);
|
|
59636
60068
|
io.out(
|
|
59637
60069
|
`mcp ${allowance.usedToday} today, ${allowance.usedThisRun} this run${allowance.reason ? `: ${allowance.reason}` : ""}`
|
|
59638
60070
|
);
|
|
@@ -59640,8 +60072,7 @@ var budgetCommand = (program2, io, finish, cli) => {
|
|
|
59640
60072
|
});
|
|
59641
60073
|
};
|
|
59642
60074
|
var outlineCommand = (program2, io, finish, cli) => {
|
|
59643
|
-
program2.command("outline").description("read
|
|
59644
|
-
const root = resolve2(io.cwd, options.root);
|
|
60075
|
+
program2.command("outline").description("read each product file's frames into its design's outline/").option(...CONFIG_OPTION).option(...PRODUCT_OPTION).option("--frames <ids>", "only these frame ids, comma separated").action(async (options) => {
|
|
59645
60076
|
const report = (summary) => io.out(
|
|
59646
60077
|
summary.skipped ? "outline is current; nothing read" : `read ${summary.read} frames, wrote ${summary.written.length} outlines, ${summary.unmapped} unmapped`
|
|
59647
60078
|
);
|
|
@@ -59651,9 +60082,15 @@ var outlineCommand = (program2, io, finish, cli) => {
|
|
|
59651
60082
|
return;
|
|
59652
60083
|
}
|
|
59653
60084
|
try {
|
|
60085
|
+
const workspace = await workspaceOf(io, options);
|
|
60086
|
+
onlyWithOne(workspace, "zaku outline", "--frames", options.frames);
|
|
59654
60087
|
const frames = options.frames ? options.frames.split(",") : null;
|
|
59655
|
-
|
|
59656
|
-
|
|
60088
|
+
finish(
|
|
60089
|
+
await forEachProduct(io, workspace, async ({ root, config: config2 }) => {
|
|
60090
|
+
report(await cli.bus.send(new WriteOutline({ root, config: config2, frames })));
|
|
60091
|
+
return 0;
|
|
60092
|
+
})
|
|
60093
|
+
);
|
|
59657
60094
|
} finally {
|
|
59658
60095
|
await recordRestCalls(cli, io);
|
|
59659
60096
|
}
|
|
@@ -59661,8 +60098,8 @@ var outlineCommand = (program2, io, finish, cli) => {
|
|
|
59661
60098
|
};
|
|
59662
60099
|
var libraryCommand = (program2, io, finish, cli) => {
|
|
59663
60100
|
const library = program2.command("library").description("snapshot the library's components and tokens");
|
|
59664
|
-
library.command("script").description("print the Plugin API code that exports the library variables, for use_figma").option(
|
|
59665
|
-
const config2 = await
|
|
60101
|
+
library.command("script").description("print the Plugin API code that exports the library variables, for use_figma").option(...CONFIG_OPTION).option(...PRODUCT_OPTION).option("--local", "also list the file's own components, for a library in the product file").option("--page <name>", "with --local, list only this page; one use_figma call per page").action(async (options) => {
|
|
60102
|
+
const { config: config2 } = oneProduct(await workspaceOf(io, options), "zaku library script");
|
|
59666
60103
|
io.out(
|
|
59667
60104
|
libraryExportScript({
|
|
59668
60105
|
combos: [config2.modes],
|
|
@@ -59694,23 +60131,13 @@ var libraryCommand = (program2, io, finish, cli) => {
|
|
|
59694
60131
|
);
|
|
59695
60132
|
library.command("save").description(
|
|
59696
60133
|
"write a library's snapshot from its components over Figma REST, joined to the variables export, or a kit's published components"
|
|
59697
|
-
).option(
|
|
60134
|
+
).option(...CONFIG_OPTION).option(...PRODUCT_OPTION).option("--key <key>", "the library or kit to save, as zaku.yaml lists it; needed when it lists several").option(
|
|
59698
60135
|
"--input <variables.json>",
|
|
59699
60136
|
"what use_figma returned for zaku library script; once per page export for a library in the product file",
|
|
59700
60137
|
(value, previous = []) => [...previous, value]
|
|
59701
60138
|
).action(async (options) => {
|
|
59702
|
-
const root =
|
|
59703
|
-
const
|
|
59704
|
-
let target;
|
|
59705
|
-
try {
|
|
59706
|
-
target = librarySaveTarget(config2, options.key);
|
|
59707
|
-
} catch (error62) {
|
|
59708
|
-
const refusal = refusalOf(error62);
|
|
59709
|
-
if (!refusal) throw error62;
|
|
59710
|
-
io.err(refusal.line);
|
|
59711
|
-
finish(refusal.code);
|
|
59712
|
-
return;
|
|
59713
|
-
}
|
|
60139
|
+
const { root, config: config2 } = oneProduct(await workspaceOf(io, options), "zaku library save");
|
|
60140
|
+
const target = librarySaveTarget(config2, options.key);
|
|
59714
60141
|
if (target.kind === "library" && (!options.input || options.input.length === 0)) {
|
|
59715
60142
|
io.err("zaku library save needs --input, the variables use_figma returned for zaku library script");
|
|
59716
60143
|
finish(3);
|
|
@@ -59724,7 +60151,7 @@ var libraryCommand = (program2, io, finish, cli) => {
|
|
|
59724
60151
|
const part = target.kind === "library" ? mergeParts(
|
|
59725
60152
|
await Promise.all(
|
|
59726
60153
|
(options.input ?? []).map(
|
|
59727
|
-
async (input2) => parseDesignFile(input2, await
|
|
60154
|
+
async (input2) => parseDesignFile(input2, await readFile7(resolve3(io.cwd, input2), "utf8"), variablePartSchema)
|
|
59728
60155
|
)
|
|
59729
60156
|
)
|
|
59730
60157
|
) : void 0;
|
|
@@ -59732,6 +60159,7 @@ var libraryCommand = (program2, io, finish, cli) => {
|
|
|
59732
60159
|
const saved = await cli.bus.send(
|
|
59733
60160
|
new SaveLibrary({
|
|
59734
60161
|
root,
|
|
60162
|
+
config: config2,
|
|
59735
60163
|
...options.key !== void 0 ? { key: options.key } : {},
|
|
59736
60164
|
...part ? { part } : {}
|
|
59737
60165
|
})
|
|
@@ -59760,13 +60188,13 @@ var libraryCommand = (program2, io, finish, cli) => {
|
|
|
59760
60188
|
};
|
|
59761
60189
|
var rulesCommand = (program2, io, finish) => {
|
|
59762
60190
|
const rules = program2.command("rules").description("zaku's rule checks, for a run that reaches Figma through use_figma");
|
|
59763
|
-
rules.command("script").description("print the Plugin API code that runs the rules over a page or a node, for use_figma").option(
|
|
60191
|
+
rules.command("script").description("print the Plugin API code that runs the rules over a page or a node, for use_figma").option(...CONFIG_OPTION).option(...PRODUCT_OPTION).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) => {
|
|
59764
60192
|
if (options.page === void 0 === (options.node === void 0)) {
|
|
59765
60193
|
io.err("zaku rules script needs --page or --node, one of them");
|
|
59766
60194
|
finish(3);
|
|
59767
60195
|
return;
|
|
59768
60196
|
}
|
|
59769
|
-
const config2 = await
|
|
60197
|
+
const { config: config2 } = oneProduct(await workspaceOf(io, options), "zaku rules script");
|
|
59770
60198
|
const scope = options.node !== void 0 ? { nodeId: options.node } : { page: options.page };
|
|
59771
60199
|
const graph = designGraph(config2);
|
|
59772
60200
|
const file2 = options.key === void 0 ? graph.libraries.length === 1 ? graph.libraries[0] : void 0 : graph.libraries.find((library2) => library2.key === options.key);
|
|
@@ -59786,7 +60214,7 @@ return ${check2};`);
|
|
|
59786
60214
|
finish(0);
|
|
59787
60215
|
return;
|
|
59788
60216
|
}
|
|
59789
|
-
const write2 = await
|
|
60217
|
+
const write2 = await readFile7(resolve3(io.cwd, options.after), "utf8");
|
|
59790
60218
|
const body = [
|
|
59791
60219
|
library,
|
|
59792
60220
|
`const zakuWrite = async () => {
|
|
@@ -59818,6 +60246,7 @@ var COMMANDS = [
|
|
|
59818
60246
|
budgetCommand,
|
|
59819
60247
|
schemaCommand,
|
|
59820
60248
|
librariesCommand,
|
|
60249
|
+
productsCommand,
|
|
59821
60250
|
mcpCommand
|
|
59822
60251
|
];
|
|
59823
60252
|
async function main(argv, io) {
|
|
@@ -59854,6 +60283,11 @@ async function main(argv, io) {
|
|
|
59854
60283
|
io.err(USAGE);
|
|
59855
60284
|
return 3;
|
|
59856
60285
|
}
|
|
60286
|
+
const refusal = refusalOf(error62);
|
|
60287
|
+
if (refusal) {
|
|
60288
|
+
io.err(refusal.line);
|
|
60289
|
+
return refusal.code;
|
|
60290
|
+
}
|
|
59857
60291
|
io.err(`zaku: ${error62 instanceof Error ? error62.message : String(error62)}`);
|
|
59858
60292
|
return 1;
|
|
59859
60293
|
}
|