@bridge-ds/core 0.9.0 → 0.10.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 +27 -1
- package/bridge.config.schema.json +23 -0
- package/dist/audit/index.js +3 -3
- package/dist/config.d.ts +28 -0
- package/dist/docs-proposal.d.ts +58 -10
- package/dist/figma-push-github.d.ts +143 -0
- package/dist/figma-push.d.ts +204 -0
- package/dist/github-client.d.ts +6 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +998 -2861
- package/dist/index.js.map +1 -1
- package/dist/node/git-local.d.ts +15 -0
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +201 -10
- package/dist/node/index.js.map +1 -1
- package/dist/node/suggestion-apply-node.d.ts +69 -0
- package/dist/{pr-composer-D2SZm7cg.js → prod-branch-BdMPKffE.js} +491 -173
- package/dist/prod-branch-BdMPKffE.js.map +1 -0
- package/dist/prod-branch-github.d.ts +28 -7
- package/dist/prod-branch.d.ts +17 -7
- package/dist/{report-DY_peRy4.js → report-DOnKUw8G.js} +2 -2
- package/dist/{report-DY_peRy4.js.map → report-DOnKUw8G.js.map} +1 -1
- package/dist/suggestion-apply-ByBEYtct.js +4802 -0
- package/dist/suggestion-apply-ByBEYtct.js.map +1 -0
- package/dist/suggestion-apply.d.ts +150 -0
- package/dist/suggestion-review.d.ts +70 -0
- package/dist/suggestions-github.d.ts +131 -0
- package/dist/suggestions.d.ts +236 -0
- package/dist/token-proposal.d.ts +51 -0
- package/package.json +1 -1
- package/dist/component-spec-BzfBkYRD.js +0 -1122
- package/dist/component-spec-BzfBkYRD.js.map +0 -1
- package/dist/pr-composer-D2SZm7cg.js.map +0 -1
- package/dist/prod-branch-D5Tl87Wf.js +0 -266
- package/dist/prod-branch-D5Tl87Wf.js.map +0 -1
|
@@ -1062,8 +1062,8 @@ function groupsPhrase(groups) {
|
|
|
1062
1062
|
return `a ${g.join(" or ")} owner`;
|
|
1063
1063
|
}
|
|
1064
1064
|
function whoCanShipSentence(policy) {
|
|
1065
|
-
const
|
|
1066
|
-
return `Only ${groupsPhrase(policy.groups)} can merge this${
|
|
1065
|
+
const names2 = (policy.entries ?? policy.logins).map((l) => entryLabel(l, policy.teams)).join(", ");
|
|
1066
|
+
return `Only ${groupsPhrase(policy.groups)} can merge this${names2 ? ` (${names2})` : ""}.`;
|
|
1067
1067
|
}
|
|
1068
1068
|
const DEFAULT_VISUAL_IMPACT = { mode: "auto" };
|
|
1069
1069
|
const VISUAL_CHECK_LABEL = "visual-check";
|
|
@@ -1175,6 +1175,8 @@ function sameProducts(a, b) {
|
|
|
1175
1175
|
return norm2(a) === norm2(b);
|
|
1176
1176
|
}
|
|
1177
1177
|
const CONFIG_FILE = "bridge.config.json";
|
|
1178
|
+
const CHANGES_MODES = ["suggest", "direct"];
|
|
1179
|
+
const DEFAULT_CHANGES_MODE = "suggest";
|
|
1178
1180
|
const DEFAULT_OVERRIDE = { allowed: [], requireReason: true, minReasonLength: 20 };
|
|
1179
1181
|
const DEFAULT_TOKEN_PATHS = {
|
|
1180
1182
|
root: "tokens",
|
|
@@ -1314,6 +1316,8 @@ function defineConfig(input) {
|
|
|
1314
1316
|
...g.rights ? { rights: normalizeRights(g.rights) } : {}
|
|
1315
1317
|
},
|
|
1316
1318
|
products: input.products?.length ? input.products.map((p) => ({ ...p })) : DEFAULT_PRODUCTS.map((p) => ({ ...p })),
|
|
1319
|
+
changes: input.changes === "direct" ? "direct" : DEFAULT_CHANGES_MODE,
|
|
1320
|
+
...input.storybook?.url ? { storybook: { url: input.storybook.url.trim().replace(/\/+$/, "") } } : {},
|
|
1317
1321
|
...input.audit ? { audit: { ...input.audit } } : {},
|
|
1318
1322
|
...input.visualImpact ? { visualImpact: { mode: input.visualImpact.mode === "on-demand" ? "on-demand" : "auto" } } : {},
|
|
1319
1323
|
...input.integrations ? { integrations: { ...input.integrations } } : {},
|
|
@@ -1436,6 +1440,13 @@ function loadConfig(source) {
|
|
|
1436
1440
|
}
|
|
1437
1441
|
}
|
|
1438
1442
|
problems.push(...visualImpactProblems(d.visualImpact));
|
|
1443
|
+
if (d.changes !== void 0 && !CHANGES_MODES.includes(d.changes)) problems.push(`"changes" must be "suggest" or "direct" (got ${JSON.stringify(d.changes)})`);
|
|
1444
|
+
const sb = d.storybook;
|
|
1445
|
+
if (sb !== void 0) {
|
|
1446
|
+
if (!isObj(sb) || !isStr(sb.url)) problems.push('"storybook" must be { "url" } with the deployed Storybook address');
|
|
1447
|
+
else if (!/^https:\/\/[^\s/]+/.test(sb.url.trim())) problems.push('"storybook.url" must start with https://, for example https://storybook.example.com');
|
|
1448
|
+
else for (const k of Object.keys(sb)) if (k !== "url") problems.push(`"storybook.${k}" is not a known key`);
|
|
1449
|
+
}
|
|
1439
1450
|
problems.push(...productProblems(d.products));
|
|
1440
1451
|
const audit = d.audit;
|
|
1441
1452
|
if (audit !== void 0) {
|
|
@@ -1468,6 +1479,13 @@ function loadConfig(source) {
|
|
|
1468
1479
|
const tokensPath = (config, rel = "") => [config.tokens.root === "." ? "" : config.tokens.root, rel].filter(Boolean).join("/");
|
|
1469
1480
|
const protectedBranchesOf = (config) => [.../* @__PURE__ */ new Set([...config.governance.protectedBranches, ...config.repo ? [config.repo.defaultBranch] : []])];
|
|
1470
1481
|
const baseBranchOf = (config) => config.repo?.defaultBranch ?? "main";
|
|
1482
|
+
const changesMode = (config) => config?.changes === "direct" ? "direct" : DEFAULT_CHANGES_MODE;
|
|
1483
|
+
function storybookUrl(config) {
|
|
1484
|
+
const explicit = config?.storybook?.url?.trim();
|
|
1485
|
+
if (explicit) return explicit.replace(/\/+$/, "");
|
|
1486
|
+
const prod = config?.previews?.production?.storybook?.trim();
|
|
1487
|
+
return prod && /^https:\/\//.test(prod) && !/\{\w+\}/.test(prod) ? prod.replace(/\/+$/, "") : void 0;
|
|
1488
|
+
}
|
|
1471
1489
|
function toConfigJson(config, schema = "./packages/core/bridge.config.schema.json") {
|
|
1472
1490
|
return {
|
|
1473
1491
|
$schema: schema,
|
|
@@ -1484,6 +1502,8 @@ function toConfigJson(config, schema = "./packages/core/bridge.config.schema.jso
|
|
|
1484
1502
|
...config.audit ? { audit: config.audit } : {},
|
|
1485
1503
|
...config.previews ? { previews: config.previews } : {},
|
|
1486
1504
|
...config.visualImpact ? { visualImpact: config.visualImpact } : {},
|
|
1505
|
+
changes: changesMode(config),
|
|
1506
|
+
...config.storybook ? { storybook: config.storybook } : {},
|
|
1487
1507
|
...config.products && !sameProducts(config.products, DEFAULT_PRODUCTS) ? { products: config.products } : {}
|
|
1488
1508
|
};
|
|
1489
1509
|
}
|
|
@@ -2193,7 +2213,7 @@ function indexByPath(tokens) {
|
|
|
2193
2213
|
for (const t of tokens) m.set(t.path, t);
|
|
2194
2214
|
return m;
|
|
2195
2215
|
}
|
|
2196
|
-
const has = (segments, ...
|
|
2216
|
+
const has = (segments, ...names2) => names2.some((n) => segments.includes(n));
|
|
2197
2217
|
function defaultScopes(path, type, tier) {
|
|
2198
2218
|
const s = path.split(".");
|
|
2199
2219
|
switch (type) {
|
|
@@ -2376,8 +2396,8 @@ function contrastScope(set) {
|
|
|
2376
2396
|
overrides: set.overrideIndex
|
|
2377
2397
|
};
|
|
2378
2398
|
}
|
|
2379
|
-
const cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
2380
|
-
const contextLabel = (r) => r.brand ? `${cap(r.brand)} ${r.theme}` : cap(r.theme);
|
|
2399
|
+
const cap$1 = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
2400
|
+
const contextLabel = (r) => r.brand ? `${cap$1(r.brand)} ${r.theme}` : cap$1(r.theme);
|
|
2381
2401
|
function renderedColor(value) {
|
|
2382
2402
|
const c = parseColor(value);
|
|
2383
2403
|
const hex = value && typeof value === "object" ? value.hex : void 0;
|
|
@@ -2600,22 +2620,296 @@ ${body}
|
|
|
2600
2620
|
|
|
2601
2621
|
${footer}`;
|
|
2602
2622
|
}
|
|
2623
|
+
const PIECES_MARK = "bridge-pieces";
|
|
2624
|
+
const NEEDED_MARK = "bridge-needed-by";
|
|
2625
|
+
const SECTION = "### Missing from the library";
|
|
2626
|
+
const NEEDED_BY_LABEL = "needed-by-product";
|
|
2627
|
+
const hiddenJson = (mark, data) => `<!-- ${mark} ${JSON.stringify(data).replace(/-->/g, "--\\u003e")} -->`;
|
|
2628
|
+
const readHidden = (mark, body) => {
|
|
2629
|
+
if (!body) return void 0;
|
|
2630
|
+
const m = new RegExp(`<!-- ${mark} (\\{[\\s\\S]*?\\}) -->`).exec(body);
|
|
2631
|
+
if (!m) return void 0;
|
|
2632
|
+
try {
|
|
2633
|
+
return JSON.parse(m[1]);
|
|
2634
|
+
} catch {
|
|
2635
|
+
return void 0;
|
|
2636
|
+
}
|
|
2637
|
+
};
|
|
2638
|
+
const KIND_WORD = { "token-change": "token change", exploration: "library exploration", request: "component request", suggestion: "suggested token change" };
|
|
2639
|
+
function parsePiecesRecord(body) {
|
|
2640
|
+
const r = readHidden(PIECES_MARK, body);
|
|
2641
|
+
if (!r || !Array.isArray(r.pieces) || !Array.isArray(r.links) || typeof r.checkedAt !== "string") return void 0;
|
|
2642
|
+
return r;
|
|
2643
|
+
}
|
|
2644
|
+
function piecesSection(r) {
|
|
2645
|
+
const link = (p) => r.links.find((l) => l.piece === p.id);
|
|
2646
|
+
const lines = r.pieces.length ? r.pieces.map((p) => {
|
|
2647
|
+
const l = link(p);
|
|
2648
|
+
return `- **${p.title}**: ${p.summary}${l ? ` ${cap(KIND_WORD[l.kind])}: #${l.number}.` : " No library branch yet."}`;
|
|
2649
|
+
}) : ["- Nothing: every value and component comes from the library."];
|
|
2650
|
+
return [SECTION, "", `Checked ${r.checkedAt.slice(0, 10)}${r.headSha ? ` on ${r.headSha.slice(0, 7)}` : ""} by Bridge.`, "", ...lines, "", hiddenJson(PIECES_MARK, r)].join("\n");
|
|
2651
|
+
}
|
|
2652
|
+
function withPiecesRecord(body, r) {
|
|
2653
|
+
const b = (body ?? "").trimEnd();
|
|
2654
|
+
const start = b.indexOf(SECTION);
|
|
2655
|
+
const markAt = b.indexOf(`<!-- ${PIECES_MARK} `);
|
|
2656
|
+
if (start >= 0 && markAt > start) {
|
|
2657
|
+
const end = b.indexOf("-->", markAt);
|
|
2658
|
+
return `${b.slice(0, start)}${piecesSection(r)}${end >= 0 ? b.slice(end + 3) : ""}`.trimEnd();
|
|
2659
|
+
}
|
|
2660
|
+
return `${b}${b ? "\n\n" : ""}${piecesSection(r)}`;
|
|
2661
|
+
}
|
|
2662
|
+
function mergePiecesRecord(prev, next) {
|
|
2663
|
+
const links = [...prev?.links ?? []];
|
|
2664
|
+
for (const l of next.links ?? []) {
|
|
2665
|
+
const at = links.findIndex((x) => x.piece === l.piece);
|
|
2666
|
+
if (at >= 0) links[at] = l;
|
|
2667
|
+
else links.push(l);
|
|
2668
|
+
}
|
|
2669
|
+
return { ...next, links };
|
|
2670
|
+
}
|
|
2671
|
+
function withLink(r, l) {
|
|
2672
|
+
return { ...r, links: [...r.links.filter((x) => x.piece !== l.piece), l] };
|
|
2673
|
+
}
|
|
2674
|
+
function neededBySection(n) {
|
|
2675
|
+
const who = n.author ? ` for @${n.author}` : "";
|
|
2676
|
+
const near = n.nearest ? ` The closest the library has today is ${n.nearest}${n.nearestToken ? ` (\`${n.nearestToken}\`)` : ""}.` : "";
|
|
2677
|
+
return [`**Needed by:** [${n.title}](${n.url}) (#${n.pr}) in ${n.productName}${who}.${near}`, "", hiddenJson(NEEDED_MARK, n)].join("\n");
|
|
2678
|
+
}
|
|
2679
|
+
function parseNeededBy(body) {
|
|
2680
|
+
const n = readHidden(NEEDED_MARK, body);
|
|
2681
|
+
return n && typeof n.pr === "number" && typeof n.title === "string" && typeof n.piece === "string" ? n : void 0;
|
|
2682
|
+
}
|
|
2683
|
+
function withNeededBy(body, n) {
|
|
2684
|
+
let b = (body ?? "").trim();
|
|
2685
|
+
const at = b.indexOf("**Needed by:**");
|
|
2686
|
+
const mark = b.indexOf(`<!-- ${NEEDED_MARK} `);
|
|
2687
|
+
if (at >= 0 && mark > at) {
|
|
2688
|
+
const end = b.indexOf("-->", mark);
|
|
2689
|
+
b = `${b.slice(0, at)}${b.slice(end + 3)}`.trim();
|
|
2690
|
+
}
|
|
2691
|
+
return `${neededBySection(n)}${b ? `
|
|
2692
|
+
|
|
2693
|
+
${b}` : ""}`;
|
|
2694
|
+
}
|
|
2695
|
+
const cap = (s) => s ? s.charAt(0).toUpperCase() + s.slice(1) : s;
|
|
2696
|
+
const forLine = (b) => `${b.productName} needs it for "${b.title.replace(/"/g, "'")}" (#${b.pr})`;
|
|
2697
|
+
function libraryBranchPlan(piece, branch, opts = {}) {
|
|
2698
|
+
const neededBy = {
|
|
2699
|
+
pr: branch.pr,
|
|
2700
|
+
title: branch.title,
|
|
2701
|
+
branch: branch.branch,
|
|
2702
|
+
url: branch.url,
|
|
2703
|
+
product: branch.productKey,
|
|
2704
|
+
productName: branch.productName,
|
|
2705
|
+
...branch.author ? { author: branch.author } : {},
|
|
2706
|
+
piece: piece.id,
|
|
2707
|
+
pieceTitle: piece.title,
|
|
2708
|
+
...piece.nearest ? { nearest: piece.nearest.label, nearestToken: piece.nearest.token } : {}
|
|
2709
|
+
};
|
|
2710
|
+
const near = piece.nearest ? ` The closest the library has today is ${piece.nearest.label} (${piece.nearest.token}, ${piece.nearest.value}).` : "";
|
|
2711
|
+
if (piece.kind === "token" && piece.token) {
|
|
2712
|
+
const t = piece.token;
|
|
2713
|
+
const files = t.files.length ? t.files : [void 0];
|
|
2714
|
+
const edits = files.map((file) => ({
|
|
2715
|
+
op: "add",
|
|
2716
|
+
path: t.path,
|
|
2717
|
+
type: t.type,
|
|
2718
|
+
value: t.value,
|
|
2719
|
+
description: `${cap(piece.name)}: ${forLine(branch)}.${files.length > 1 ? " Same value in every theme: review it in each." : ""}`,
|
|
2720
|
+
...file ? { file } : {}
|
|
2721
|
+
}));
|
|
2722
|
+
return { kind: "token-change", title: `Add ${t.path}`, summary: `${forLine(branch)}: ${piece.summary}${near}`, edits, neededBy };
|
|
2723
|
+
}
|
|
2724
|
+
if (piece.kind === "variant" && piece.component && opts.mode === "suggest") {
|
|
2725
|
+
const request2 = {
|
|
2726
|
+
component: piece.component,
|
|
2727
|
+
kind: "new-variant",
|
|
2728
|
+
title: piece.title,
|
|
2729
|
+
summary: `${forLine(branch)}: ${piece.summary}${near}`,
|
|
2730
|
+
changes: piece.values.slice(0, 6).map((v) => ({ field: v.property ?? v.category, after: v.value })),
|
|
2731
|
+
source: opts.source ?? "mcp",
|
|
2732
|
+
...opts.requestedBy ? { requestedBy: opts.requestedBy } : {}
|
|
2733
|
+
};
|
|
2734
|
+
return { kind: "request", title: piece.title, request: request2, neededBy };
|
|
2735
|
+
}
|
|
2736
|
+
if (piece.kind === "variant" && piece.component) {
|
|
2737
|
+
const values = piece.values.map((v) => `${v.property ?? v.category} ${v.value}`).join(", ");
|
|
2738
|
+
const exploration = {
|
|
2739
|
+
name: piece.title,
|
|
2740
|
+
purpose: `${forLine(branch)}: ${/^[aeiou]/i.test(piece.name) ? "an" : "a"} ${piece.name} ${piece.aspect ?? "style"} on ${piece.component} (${values}).${near}`,
|
|
2741
|
+
useCase: "terminal",
|
|
2742
|
+
experimental: [piece.title],
|
|
2743
|
+
source: opts.source === "figma" ? "figma" : opts.source ?? "mcp"
|
|
2744
|
+
};
|
|
2745
|
+
const brief = [
|
|
2746
|
+
`Add the ${piece.name} ${piece.aspect ?? "style"} to ${piece.component} in the library, on this exploration branch.`,
|
|
2747
|
+
`The product branch writes it by hand: ${values}. Express it with tokens (a component or semantic token per value), add it to the component's props, docs and examples, and keep every existing ${piece.component} unchanged.`,
|
|
2748
|
+
piece.nearest ? `Say in the pull request why ${piece.nearest.label} is not enough, or recommend it instead.` : ""
|
|
2749
|
+
].filter(Boolean).join(" ");
|
|
2750
|
+
return { kind: "exploration", title: piece.title, exploration, neededBy, brief };
|
|
2751
|
+
}
|
|
2752
|
+
const name = piece.component ?? cap(piece.name);
|
|
2753
|
+
const request = {
|
|
2754
|
+
component: name,
|
|
2755
|
+
kind: "new-component",
|
|
2756
|
+
title: `Add ${name}`,
|
|
2757
|
+
summary: `${forLine(branch)}: ${piece.summary}${near}`,
|
|
2758
|
+
changes: piece.values.slice(0, 6).map((v) => ({ field: v.property ?? v.category, after: v.value })),
|
|
2759
|
+
source: opts.source ?? "mcp",
|
|
2760
|
+
...opts.requestedBy ? { requestedBy: opts.requestedBy } : {}
|
|
2761
|
+
};
|
|
2762
|
+
return { kind: "request", title: `New component: ${name}`, request, neededBy };
|
|
2763
|
+
}
|
|
2764
|
+
const STATUS_LABEL = {
|
|
2765
|
+
draft: "Draft",
|
|
2766
|
+
"in-review": "In review",
|
|
2767
|
+
changes: "Changes requested",
|
|
2768
|
+
approved: "Approved",
|
|
2769
|
+
shipped: "Shipped",
|
|
2770
|
+
closed: "Closed",
|
|
2771
|
+
exploring: "Being built",
|
|
2772
|
+
requested: "Requested",
|
|
2773
|
+
"in-progress": "In progress",
|
|
2774
|
+
done: "Done",
|
|
2775
|
+
declined: "Declined",
|
|
2776
|
+
outdated: "Outdated"
|
|
2777
|
+
};
|
|
2778
|
+
const LINK_STATUS_TONE = {
|
|
2779
|
+
draft: "neutral",
|
|
2780
|
+
"in-review": "info",
|
|
2781
|
+
changes: "warning",
|
|
2782
|
+
approved: "success",
|
|
2783
|
+
shipped: "success",
|
|
2784
|
+
closed: "neutral",
|
|
2785
|
+
exploring: "neutral",
|
|
2786
|
+
requested: "neutral",
|
|
2787
|
+
"in-progress": "info",
|
|
2788
|
+
done: "success",
|
|
2789
|
+
declined: "neutral",
|
|
2790
|
+
outdated: "warning"
|
|
2791
|
+
};
|
|
2792
|
+
const names = (people2) => people2.length <= 2 ? people2.map((p) => `@${p}`).join(" and ") : `@${people2[0]} and ${people2.length - 1} more`;
|
|
2793
|
+
const SUGGESTION_LINK_STATUS = {
|
|
2794
|
+
"needs-review": "in-review",
|
|
2795
|
+
"changes-requested": "changes",
|
|
2796
|
+
approved: "approved",
|
|
2797
|
+
applying: "in-progress",
|
|
2798
|
+
applied: "shipped",
|
|
2799
|
+
declined: "declined",
|
|
2800
|
+
outdated: "outdated"
|
|
2801
|
+
};
|
|
2802
|
+
function linkStatus(x) {
|
|
2803
|
+
const make = (key, people2 = [], verb = "reviews") => {
|
|
2804
|
+
const label = STATUS_LABEL[key];
|
|
2805
|
+
const tail = people2.length ? ` · ${names(people2)} ${people2.length === 1 ? verb : verb.replace(/s$/, "")}` : "";
|
|
2806
|
+
return { key, label, people: people2, line: `${label}${tail}` };
|
|
2807
|
+
};
|
|
2808
|
+
if (x.kind === "suggestion") {
|
|
2809
|
+
const key = SUGGESTION_LINK_STATUS[x.status];
|
|
2810
|
+
return make(key, key === "in-progress" ? [...x.assignees ?? []] : [], "builds");
|
|
2811
|
+
}
|
|
2812
|
+
if (x.kind === "request") {
|
|
2813
|
+
if (x.state === "closed") return make(x.stateReason === "not_planned" ? "declined" : "done");
|
|
2814
|
+
return x.implemented ? make("in-progress", [...x.assignees ?? []], "builds") : make("requested", [...x.assignees ?? []], "builds");
|
|
2815
|
+
}
|
|
2816
|
+
if (x.state === "merged") return make("shipped");
|
|
2817
|
+
if (x.state !== "open") return make("closed");
|
|
2818
|
+
if ((x.labels ?? []).includes("exploration")) return make("exploring");
|
|
2819
|
+
if (x.draft) return make("draft");
|
|
2820
|
+
const latest = /* @__PURE__ */ new Map();
|
|
2821
|
+
for (const r of x.reviews ?? []) if (r.user && r.state !== "COMMENTED") latest.set(r.user, r.state);
|
|
2822
|
+
const states = [...latest.values()];
|
|
2823
|
+
if (states.includes("CHANGES_REQUESTED")) return make("changes", [...latest].filter(([, s]) => s === "CHANGES_REQUESTED").map(([u]) => u), "asks");
|
|
2824
|
+
const waiting = [...x.requestedReviewers ?? []];
|
|
2825
|
+
if (states.includes("APPROVED") && !waiting.length) return make("approved");
|
|
2826
|
+
return make("in-review", waiting);
|
|
2827
|
+
}
|
|
2828
|
+
function libraryPreviewState(x) {
|
|
2829
|
+
if (x.kind === "suggestion") {
|
|
2830
|
+
if (x.lifecycle === "closed") return { key: "declined", sentence: `The library declined this suggestion.${x.nearest ? ` Ask Claude to use ${x.nearest} instead.` : ""}`, action: null };
|
|
2831
|
+
if (x.lifecycle === "merged") return x.behindMain === 0 ? { key: "switched", sentence: "Your branch uses the published version.", action: null } : { key: "published", sentence: "The library applied the suggestion. Switch your branch to the published version.", action: { kind: "switch", label: "Switch to the published version" } };
|
|
2832
|
+
return { key: "nothing-yet", sentence: "Nothing to preview yet: owners review the suggestion, then a developer applies it. Your branch keeps its own value until then.", action: null };
|
|
2833
|
+
}
|
|
2834
|
+
if (x.kind === "request") {
|
|
2835
|
+
if (x.lifecycle === "closed") return { key: "declined", sentence: `The library declined this request.${x.nearest ? ` Ask Claude to use ${x.nearest} instead.` : ""}`, action: null };
|
|
2836
|
+
if (x.lifecycle === "merged") return x.behindMain === 0 ? { key: "switched", sentence: "Your branch uses the published version.", action: null } : { key: "published", sentence: "The library built it. Switch your branch to the published version, then ask Claude to use it.", action: { kind: "switch", label: "Switch to the published version" } };
|
|
2837
|
+
return { key: "nothing-yet", sentence: "Nothing to preview yet: the library builds it first. Your branch keeps its own version until then.", action: null };
|
|
2838
|
+
}
|
|
2839
|
+
if (x.lifecycle === "merged") {
|
|
2840
|
+
if (x.behindMain === 0) return { key: "switched", sentence: "Your branch uses the published version.", action: null };
|
|
2841
|
+
return { key: "published", sentence: "The library published it. Switch your branch to the published version.", action: { kind: "switch", label: "Switch to the published version" } };
|
|
2842
|
+
}
|
|
2843
|
+
if (x.lifecycle === "closed") return { key: "declined", sentence: `The library closed it without shipping.${x.nearest ? ` Ask Claude to use ${x.nearest} instead.` : ""}`, action: null };
|
|
2844
|
+
if (!x.hasChanges) return { key: "nothing-yet", sentence: "The library branch has no change yet. Claude adds it there, then your branch can use its preview.", action: null };
|
|
2845
|
+
if (x.missing === 0) return { key: "preview", sentence: "Your branch uses a preview of the library branch. When the library publishes it, switch to the real version here in one click.", action: null };
|
|
2846
|
+
if (x.missing !== null && x.total !== null && x.missing < x.total) return { key: "outdated", sentence: "The library branch changed since your branch took its preview.", action: { kind: "refresh-preview", label: "Get the latest preview" } };
|
|
2847
|
+
return { key: "not-used", sentence: "Your branch does not use the library branch yet.", action: { kind: "use-preview", label: "Use its preview in my branch" } };
|
|
2848
|
+
}
|
|
2849
|
+
const nPieces = (n) => `${n} ${n === 1 ? "piece" : "pieces"}`;
|
|
2850
|
+
function productBranchSentence(r, opts = {}) {
|
|
2851
|
+
if (!r) return { lead: "Not checked against the library yet.", strong: "", rest: " Ask Claude what is missing from the library." };
|
|
2852
|
+
const n = r.pieces.length;
|
|
2853
|
+
if (!n) return { lead: "Built with the library.", strong: " Nothing is missing", rest: ": every value and component comes from it." };
|
|
2854
|
+
const linked = r.pieces.filter((p) => r.links.some((l) => l.piece === p.id));
|
|
2855
|
+
const openers = [...new Set(linked.map((p) => r.links.find((l) => l.piece === p.id)).map((l) => l.agent ? opts.agentName ?? "Claude AI" : l.openedBy && l.openedBy === opts.viewer ? "you" : l.openedBy ? `@${l.openedBy}` : "someone"))];
|
|
2856
|
+
const by = openers.length === 1 ? openers[0] : "your team";
|
|
2857
|
+
const was = n === 1 ? "was" : "were";
|
|
2858
|
+
if (linked.length === n) {
|
|
2859
|
+
const what = n === 1 ? "a library branch for it" : "library branches for them";
|
|
2860
|
+
return { lead: "Built with the library. ", strong: `${nPieces(n)} ${was} missing`, rest: `, and ${by} opened ${what}.` };
|
|
2861
|
+
}
|
|
2862
|
+
if (!linked.length) return { lead: "Built with the library. ", strong: `${nPieces(n)} ${n === 1 ? "is" : "are"} missing`, rest: n === 1 ? ": open a library branch for it." : ": open a library branch for each." };
|
|
2863
|
+
return { lead: "Built with the library. ", strong: `${nPieces(n)} ${was} missing`, rest: `: ${linked.length} ${linked.length === 1 ? "has" : "have"} a library branch, ${n - linked.length} still ${n - linked.length === 1 ? "needs" : "need"} one.` };
|
|
2864
|
+
}
|
|
2865
|
+
function whyItExists(n, opts = {}) {
|
|
2866
|
+
const who = n.author ? opts.names?.[n.author] ?? `@${n.author}` : "A product team";
|
|
2867
|
+
return { who, title: n.title, product: n.productName };
|
|
2868
|
+
}
|
|
2869
|
+
function nearestQuestion(n, opts = {}) {
|
|
2870
|
+
if (!n.nearest) return null;
|
|
2871
|
+
const who = n.author ? opts.names?.[n.author] ?? `@${n.author}` : "the product team";
|
|
2872
|
+
return `It looks a lot like "${n.nearest}". Is a new one worth it, or should ${who} use ${n.nearest}?`;
|
|
2873
|
+
}
|
|
2874
|
+
function suggestNearestComment(n) {
|
|
2875
|
+
if (!n.nearest) return null;
|
|
2876
|
+
return `Let's not add it to the library: ${n.nearest}${n.nearestToken ? ` (\`${n.nearestToken}\`)` : ""} covers it. Use it on ${n.title} (#${n.pr}) instead, then close this branch.`;
|
|
2877
|
+
}
|
|
2878
|
+
function pieceId(parts) {
|
|
2879
|
+
return slugify(parts.filter(Boolean).join(" "), 48);
|
|
2880
|
+
}
|
|
2881
|
+
const TONE_WORDS = ["neutral", "success", "warning", "danger", "info", "error", "critical", "accent", "brand", "primary", "secondary"];
|
|
2882
|
+
function tokenLabel(path) {
|
|
2883
|
+
const parts = path.split(".");
|
|
2884
|
+
const tone = parts.find((p) => TONE_WORDS.includes(p));
|
|
2885
|
+
if (tone) return tone;
|
|
2886
|
+
const meaningful = parts.filter((p) => !/^(color|bg|fg|text|border|default|base|value|\d+)$/.test(p));
|
|
2887
|
+
return meaningful[meaningful.length - 1] ?? parts[parts.length - 1] ?? path;
|
|
2888
|
+
}
|
|
2889
|
+
function proposedTokenPath(nearest, name, category) {
|
|
2890
|
+
const slug = slugify(name, 32);
|
|
2891
|
+
if (!nearest) return `${category === "color" ? "color" : category}.${slug}`;
|
|
2892
|
+
const parts = nearest.split(".");
|
|
2893
|
+
const toneAt = parts.findIndex((p) => TONE_WORDS.includes(p));
|
|
2894
|
+
if (toneAt > 0) return [...parts.slice(0, toneAt), slug, ...parts.slice(toneAt + 1)].join(".");
|
|
2895
|
+
return [...parts.slice(0, -1), slug].join(".");
|
|
2896
|
+
}
|
|
2603
2897
|
export {
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2898
|
+
layoutOptions as $,
|
|
2899
|
+
formatValue as A,
|
|
2900
|
+
resolve as B,
|
|
2901
|
+
moveToken as C,
|
|
2902
|
+
effectiveScopes as D,
|
|
2609
2903
|
EXT_ID as E,
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2904
|
+
sameScopes as F,
|
|
2905
|
+
defaultScopes as G,
|
|
2906
|
+
readTokenAt as H,
|
|
2907
|
+
modeFile as I,
|
|
2908
|
+
defaultFile as J,
|
|
2909
|
+
selectTokenFiles as K,
|
|
2910
|
+
LayeredTokenSet as L,
|
|
2911
|
+
resolveBranchPreviews as M,
|
|
2912
|
+
loadConfig as N,
|
|
2619
2913
|
tokensPath as O,
|
|
2620
2914
|
toConfigJson as P,
|
|
2621
2915
|
validateLayered as Q,
|
|
@@ -2623,166 +2917,190 @@ export {
|
|
|
2623
2917
|
SINGLE_MODE as S,
|
|
2624
2918
|
TIER_NAMES as T,
|
|
2625
2919
|
classifyRisk as U,
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2920
|
+
CONFIG_FILE as V,
|
|
2921
|
+
RISK_LABELS as W,
|
|
2922
|
+
previewLinks as X,
|
|
2923
|
+
findPreviewComment as Y,
|
|
2924
|
+
previewsSettled as Z,
|
|
2925
|
+
DEFAULT_TOKEN_PATHS as _,
|
|
2926
|
+
proposedTokenPath as a,
|
|
2927
|
+
contextFor as a$,
|
|
2928
|
+
buildTokenSet as a0,
|
|
2929
|
+
readPreviewComment as a1,
|
|
2930
|
+
linkStatus as a2,
|
|
2931
|
+
libraryPreviewState as a3,
|
|
2932
|
+
parsePiecesRecord as a4,
|
|
2933
|
+
libraryBranchPlan as a5,
|
|
2934
|
+
NEEDED_BY_LABEL as a6,
|
|
2935
|
+
withNeededBy as a7,
|
|
2936
|
+
withLink as a8,
|
|
2937
|
+
withPiecesRecord as a9,
|
|
2938
|
+
RIGHTS as aA,
|
|
2939
|
+
RIGHT_LABEL as aB,
|
|
2940
|
+
RISK_TIER as aC,
|
|
2941
|
+
TIER_ORDER as aD,
|
|
2942
|
+
TeamDirectory as aE,
|
|
2943
|
+
VISUAL_CHECK_LABEL as aF,
|
|
2944
|
+
affectedContrast as aG,
|
|
2945
|
+
aliasOf as aH,
|
|
2946
|
+
appForProject as aI,
|
|
2947
|
+
appUrl as aJ,
|
|
2948
|
+
approverEntries as aK,
|
|
2949
|
+
approverLists as aL,
|
|
2950
|
+
baseBranchOf as aM,
|
|
2951
|
+
branchName as aN,
|
|
2952
|
+
branchSlug as aO,
|
|
2953
|
+
canShip as aP,
|
|
2954
|
+
changeKind as aQ,
|
|
2955
|
+
changedModes as aR,
|
|
2956
|
+
changesMode as aS,
|
|
2957
|
+
clearRawDeep as aT,
|
|
2958
|
+
colorToCss as aU,
|
|
2959
|
+
colorsEqual as aV,
|
|
2960
|
+
comboKey as aW,
|
|
2961
|
+
commitMessage as aX,
|
|
2962
|
+
compactJson as aY,
|
|
2963
|
+
composePrBody as aZ,
|
|
2964
|
+
composite as a_,
|
|
2965
|
+
productBranchSentence as aa,
|
|
2966
|
+
mergePiecesRecord as ab,
|
|
2967
|
+
productOfBranch as ac,
|
|
2968
|
+
defaultProduct as ad,
|
|
2969
|
+
slugify as ae,
|
|
2970
|
+
AAA_MIN as af,
|
|
2971
|
+
AA_MIN as ag,
|
|
2972
|
+
CHANGES_MODES as ah,
|
|
2973
|
+
CONTRAST_CELL_MAX as ai,
|
|
2974
|
+
CONTRAST_CHECKS_FILE as aj,
|
|
2975
|
+
ConfigError as ak,
|
|
2976
|
+
DEFAULT_CHANGES_MODE as al,
|
|
2977
|
+
DEFAULT_GOVERNANCE as am,
|
|
2978
|
+
DEFAULT_OVERRIDE as an,
|
|
2979
|
+
DEFAULT_PRODUCTS as ao,
|
|
2980
|
+
DEFAULT_RIGHTS as ap,
|
|
2981
|
+
DEFAULT_VISUAL_IMPACT as aq,
|
|
2982
|
+
DTCG_TYPES as ar,
|
|
2983
|
+
JsonParseError as as,
|
|
2984
|
+
LINK_STATUS_TONE as at,
|
|
2985
|
+
OWNER_GROUPS as au,
|
|
2986
|
+
PREVIEW_APP_LABELS as av,
|
|
2987
|
+
PREVIEW_COMMENT_MARKER as aw,
|
|
2988
|
+
PREVIEW_PLACEHOLDERS as ax,
|
|
2989
|
+
PRIMITIVE_MODE as ay,
|
|
2990
|
+
PRODUCT_LABEL_PREFIX as az,
|
|
2991
|
+
modesOf as b,
|
|
2992
|
+
sameProducts as b$,
|
|
2993
|
+
contrastLevel as b0,
|
|
2994
|
+
contrastPair as b1,
|
|
2995
|
+
contrastRatio as b2,
|
|
2996
|
+
defaultContext as b3,
|
|
2997
|
+
defaultTitle as b4,
|
|
2998
|
+
defineConfig as b5,
|
|
2999
|
+
detectLayout as b6,
|
|
3000
|
+
entriesFor as b7,
|
|
3001
|
+
entryLabel as b8,
|
|
3002
|
+
expandEntries as b9,
|
|
3003
|
+
nearestQuestion as bA,
|
|
3004
|
+
neededBySection as bB,
|
|
3005
|
+
nodesEqual as bC,
|
|
3006
|
+
normalizeRights as bD,
|
|
3007
|
+
overrideKey as bE,
|
|
3008
|
+
ownerEntryProblems as bF,
|
|
3009
|
+
pairKey as bG,
|
|
3010
|
+
parseDimension as bH,
|
|
3011
|
+
parseJson as bI,
|
|
3012
|
+
parseNeededBy as bJ,
|
|
3013
|
+
parseOwnerEntry as bK,
|
|
3014
|
+
parseVercelComment as bL,
|
|
3015
|
+
piecesSection as bM,
|
|
3016
|
+
plainEqual as bN,
|
|
3017
|
+
previewComment as bO,
|
|
3018
|
+
previewLinksOf as bP,
|
|
3019
|
+
previewUrl as bQ,
|
|
3020
|
+
productForPlace as bR,
|
|
3021
|
+
productLabel as bS,
|
|
3022
|
+
productMarks as bT,
|
|
3023
|
+
productProblems as bU,
|
|
3024
|
+
productsOf as bV,
|
|
3025
|
+
projectOfLabel as bW,
|
|
3026
|
+
protectedBranchesOf as bX,
|
|
3027
|
+
renderedColor as bY,
|
|
3028
|
+
rgbaToDtcg as bZ,
|
|
3029
|
+
rightsProblems as b_,
|
|
3030
|
+
expandOwners as ba,
|
|
3031
|
+
fieldChanges as bb,
|
|
3032
|
+
findProduct as bc,
|
|
3033
|
+
findToken as bd,
|
|
3034
|
+
findVercelComment as be,
|
|
3035
|
+
flattenLayerFile as bf,
|
|
3036
|
+
formatNumber as bg,
|
|
3037
|
+
formatOwnerEntry as bh,
|
|
3038
|
+
fromPlain as bi,
|
|
3039
|
+
getChild as bj,
|
|
3040
|
+
getEntry as bk,
|
|
3041
|
+
globToRegExp as bl,
|
|
3042
|
+
groupsPhrase as bm,
|
|
3043
|
+
hexToRgba as bn,
|
|
3044
|
+
holdersOf as bo,
|
|
3045
|
+
indexByPath as bp,
|
|
3046
|
+
inheritedTypeAt as bq,
|
|
3047
|
+
installCommand as br,
|
|
3048
|
+
installCommandFromPreviewComment as bs,
|
|
3049
|
+
isGuardrail as bt,
|
|
3050
|
+
isTeamEntry as bu,
|
|
3051
|
+
isTokenFile as bv,
|
|
3052
|
+
isVercelComment as bw,
|
|
3053
|
+
kindForMin as bx,
|
|
3054
|
+
layeredParityIssues as by,
|
|
3055
|
+
luminance as bz,
|
|
3056
|
+
TIER_AXIS as c,
|
|
3057
|
+
sameToken as c0,
|
|
3058
|
+
serializeJson as c1,
|
|
3059
|
+
shipPolicy as c2,
|
|
3060
|
+
snapshotUrl as c3,
|
|
3061
|
+
storybookUrl as c4,
|
|
3062
|
+
suggestNearestComment as c5,
|
|
3063
|
+
summarizeTokenChange as c6,
|
|
3064
|
+
tarballAssetName as c7,
|
|
3065
|
+
tarballUrl as c8,
|
|
3066
|
+
teamKey as c9,
|
|
3067
|
+
teamKeyOf as ca,
|
|
3068
|
+
teamUnreadableMessage as cb,
|
|
3069
|
+
teamsIn as cc,
|
|
3070
|
+
toAlias as cd,
|
|
3071
|
+
toMap as ce,
|
|
3072
|
+
toPlain as cf,
|
|
3073
|
+
tokenBump as cg,
|
|
3074
|
+
tokenNode as ch,
|
|
3075
|
+
unreadableShipTeams as ci,
|
|
3076
|
+
unreadableTeams as cj,
|
|
3077
|
+
valueIn as ck,
|
|
3078
|
+
valueToCss as cl,
|
|
3079
|
+
visualImpactProblems as cm,
|
|
3080
|
+
whoCanShipSentence as cn,
|
|
3081
|
+
whyItExists as co,
|
|
3082
|
+
collectRefs as d,
|
|
2765
3083
|
evaluatePairs as e,
|
|
2766
3084
|
findReferenceProblems as f,
|
|
2767
|
-
|
|
2768
|
-
|
|
3085
|
+
contrastScope as g,
|
|
3086
|
+
contextLabel as h,
|
|
2769
3087
|
isMultiMode as i,
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
3088
|
+
isAlias as j,
|
|
3089
|
+
aliasTarget as k,
|
|
3090
|
+
pathId as l,
|
|
2773
3091
|
modeDisplayName as m,
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
3092
|
+
flattenTokens as n,
|
|
3093
|
+
threeWayDiff as o,
|
|
3094
|
+
pieceId as p,
|
|
3095
|
+
emptyTokenFile as q,
|
|
2778
3096
|
removeToken as r,
|
|
2779
3097
|
serializeTokenFile as s,
|
|
2780
|
-
|
|
3098
|
+
tokenLabel as t,
|
|
2781
3099
|
upsertToken as u,
|
|
2782
3100
|
valuesEqual as v,
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
3101
|
+
parseTokenFile as w,
|
|
3102
|
+
EXT_SCOPES as x,
|
|
3103
|
+
parseColor as y,
|
|
3104
|
+
rgbaToHex as z
|
|
2787
3105
|
};
|
|
2788
|
-
//# sourceMappingURL=
|
|
3106
|
+
//# sourceMappingURL=prod-branch-BdMPKffE.js.map
|