@bridge-ds/core 0.20.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/index.js +275 -52
- package/dist/audit/index.js.map +1 -1
- package/dist/audit/missing-pieces.d.ts +4 -0
- package/dist/component-spec.d.ts +13 -0
- package/dist/exploration-done-github.d.ts +50 -0
- package/dist/exploration-resume.d.ts +136 -0
- package/dist/explorations-github.d.ts +75 -3
- package/dist/explorations.d.ts +137 -8
- package/dist/figma-fix-loop.d.ts +1 -1
- package/dist/figma-fixes.d.ts +14 -2
- package/dist/github-client.d.ts +17 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1708 -1283
- package/dist/index.js.map +1 -1
- package/dist/measured-only.d.ts +13 -1
- package/dist/node/index.js +11 -11
- package/dist/previews-github.d.ts +13 -0
- package/dist/previews.d.ts +8 -1
- package/dist/{prod-branch-CJZwMfVD.js → prod-branch-C7tphFAA.js} +255 -192
- package/dist/prod-branch-C7tphFAA.js.map +1 -0
- package/dist/prod-branch-github.d.ts +54 -4
- package/dist/prod-branch.d.ts +42 -1
- package/dist/products.d.ts +17 -0
- package/dist/{repo-source-CshjjC7x.js → repo-source-CEBBBtm1.js} +2165 -1998
- package/dist/repo-source-CEBBBtm1.js.map +1 -0
- package/dist/{report-CE-jHAuw.js → report-B7wNAnSu.js} +38 -38
- package/dist/{report-CE-jHAuw.js.map → report-B7wNAnSu.js.map} +1 -1
- package/dist/review-gate.d.ts +1 -1
- package/dist/try-in-product.d.ts +4 -1
- package/package.json +1 -1
- package/dist/prod-branch-CJZwMfVD.js.map +0 -1
- package/dist/repo-source-CshjjC7x.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { m as modeDisplayName, b as modesOf$1, i as isMultiMode, T as TIER_NAMES, c as TIER_AXIS, d as collectRefs, f as findReferenceProblems, e as evaluatePairs, g as contrastScope, h as contextLabel, S as SINGLE_MODE, j as isAlias$1, k as aliasTarget, l as pathId, v as valuesEqual, n as flattenTokens, s as serializeTokenFile, r as removeToken, u as upsertToken, o as threeWayDiff, q as emptyTokenFile, w as parseTokenFile, E as EXT_ID, x as EXT_SCOPES, y as parseColor, z as rgbaToHex, A as formatValue, B as resolve, C as moveToken, D as effectiveScopes, F as sameScopes, G as defaultScopes, H as readTokenAt, I as modeFile, J as defaultFile, K as selectTokenFiles, L as LayeredTokenSet, M as resolveBranchPreviews, N as loadConfig, O as tokensPath, P as toConfigJson, Q as validateLayered, R as parseContrastChecks, U as classifyRisk, V as CONFIG_FILE, W as RISK_LABELS, X as previewLinks, Y as findPreviewComment, Z as previewsSettled, _ as
|
|
2
|
-
import {
|
|
3
|
-
import { G as GitHubError, c as collectHistory, p as packageDirCandidates, a as parseChangelog, r as releasesFromTags, m as mergeReleases, b as buildReport, d as applyTokenEdits, e as buildHistoryEntry, f as coerceValue, g as checkLayeredPair, h as formatChangeset, P as PROSE_KEYS, i as markClaudeDraft, j as cleanDraftText, k as docsPrompt, D as DRAFT_LINE_MAX, R as REQUESTS_BRANCH, l as REQUEST_KINDS, s as sanitizeDraftLine,
|
|
4
|
-
import {
|
|
1
|
+
import { m as modeDisplayName, b as modesOf$1, i as isMultiMode, T as TIER_NAMES, c as TIER_AXIS, d as collectRefs, f as findReferenceProblems, e as evaluatePairs, g as contrastScope, h as contextLabel, S as SINGLE_MODE, j as isAlias$1, k as aliasTarget, l as pathId, v as valuesEqual, n as flattenTokens, s as serializeTokenFile, r as removeToken, u as upsertToken, o as threeWayDiff, q as emptyTokenFile, w as parseTokenFile, E as EXT_ID, x as EXT_SCOPES, y as parseColor, z as rgbaToHex, A as formatValue, B as resolve, C as moveToken, D as effectiveScopes, F as sameScopes, G as defaultScopes, H as readTokenAt, I as modeFile, J as defaultFile, K as selectTokenFiles, L as LayeredTokenSet, M as resolveBranchPreviews, N as loadConfig, O as tokensPath, P as toConfigJson, Q as validateLayered, R as parseContrastChecks, U as classifyRisk, V as CONFIG_FILE, W as RISK_LABELS, X as previewLinks, Y as findPreviewComment, Z as previewsSettled, _ as previewUrl, $ as productRepos, a0 as linkStatus, a1 as libraryPreviewState, a2 as parsePiecesRecord, a3 as libraryBranchPlan, a4 as NEEDED_BY_LABEL, a5 as withNeededBy, a6 as withLink, a7 as withPiecesRecord, a8 as productBranchSentence, a9 as productOfBranch, aa as pieceRequest, ab as mergePiecesRecord, ac as defaultProduct, ad as productOfRepo, ae as baseBranchOf, af as DEFAULT_TOKEN_PATHS, ag as layoutOptions, ah as buildTokenSet, ai as readPreviewComment, aj as slugify, ak as defineConfig, al as globToRegExp, am as ConfigError, an as DEFAULT_CHANGES_MODE, ao as DEFAULT_OVERRIDE, ap as DEFAULT_PRODUCTS, aq as isGuardrail } from "./prod-branch-C7tphFAA.js";
|
|
2
|
+
import { ar, as, at, au, av, aw, ax, ay, az, aA, aB, aC, aD, aE, aF, aG, aH, aI, aJ, aK, aL, aM, aN, aO, aP, aQ, aR, aS, aT, aU, aV, aW, aX, aY, aZ, a_, a$, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn, bo, bp, bq, br, bs, bt, bu, bv, bw, bx, by, bz, bA, bB, bC, bD, bE, bF, bG, bH, bI, bJ, bK, bL, bM, bN, bO, bP, bQ, bR, bS, bT, bU, bV, bW, p, bX, bY, bZ, b_, b$, c0, c1, c2, c3, c4, c5, c6, a, c7, c8, c9, ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn, co, cp, cq, cr, cs, ct, cu, cv, cw, t, cx, cy, cz, cA, cB, cC, cD, cE, cF } from "./prod-branch-C7tphFAA.js";
|
|
3
|
+
import { G as GitHubError, c as collectHistory, p as packageDirCandidates, a as parseChangelog, r as releasesFromTags, m as mergeReleases, b as buildReport, d as applyTokenEdits, e as buildHistoryEntry, f as coerceValue, g as checkLayeredPair, h as formatChangeset, P as PROSE_KEYS, i as markClaudeDraft, j as cleanDraftText, k as docsPrompt, D as DRAFT_LINE_MAX, R as REQUESTS_BRANCH, l as REQUEST_KINDS, s as sanitizeDraftLine, E as EXPLORATION_ARCHIVED_LABEL, n as parseExplorationBody, o as EXPLORATION_PREFIX, q as explorationSlug, t as isArchivedExploration, u as explorationStatus, v as explorationTryIt, w as isExplorationPull, x as promotionPlan, y as EXPLORATION_LABEL, z as explorationProblems, A as explorationNote, B as explorationNotePath, C as explorationPrTitle, F as explorationPrBody, H as suggestionStateFromLabels, I as suggestionStatus, J as composeRequestIssue, K as EXPLORATION_NOTES_DIR, L as isExplorationBranch, M as doneExploringPlan, N as withDoneExploring, O as explorationStartingPoint, Q as explorationRefLabel, S as compareSpecToMeasured, T as variantKeyOf, U as matchVariant, V as withoutAddedWrappers, W as pairParts, X as hashSpec, Y as SPEC_FIELDS, Z as COLOR_FIELDS, _ as DRAFTED_BY_CLAUDE_LABEL, $ as overrideComment, a0 as OVERRIDE_HEADING, a1 as overrideRefusedComment, a2 as diffLayered, a3 as contrastDelta, a4 as runLayeredContrast, a5 as layeredImpact, a6 as classifyLayered, a7 as composeProposalBody, a8 as createSuggestionOnGitHub, a9 as gitBlobSha, aa as SUGGESTION_SCHEMA, ab as branchWithJiraKey, ac as titleWithJiraKey, ad as figmaSpecPath, ae as formatFigmaSpec, af as figmaDraftBrief, ag as parseFigmaOrigin, ah as figmaPushStatus, ai as parseFigmaSpec, aj as FIGMA_SPEC_DIR, ak as FROM_FIGMA_LABEL, al as withFigmaOrigin, am as WAITING_FOR_CLAUDE_LABEL, an as planComponentPush, ao as figmaOriginSection, ap as figmaBranchTitle, aq as figmaSpecSlug, ar as figmaDraftBody, as as REQUEST_LABEL, at as figmaNodeUrl, au as parentDir, av as parseComponentSpecs, aw as readRepoTexts, ax as normalizeRepoPath, ay as isUnder, az as componentMotion, aA as GitHubClient, aB as effectiveTier, aC as parseRequestIssue, aD as requestStatus, aE as listSuggestionsOnGitHub, aF as getSuggestionOnGitHub, aG as closingIssueNumbers, aH as requestIssueTitle, aI as pullState, aJ as summarizeCi, aK as summarizeApprovals } from "./repo-source-CEBBBtm1.js";
|
|
4
|
+
import { aL as aL2, aM as aM2, aN as aN2, aO as aO2, aP as aP2, aQ as aQ2, aR as aR2, aS as aS2, aT as aT2, aU as aU2, aV as aV2, aW as aW2, aX as aX2, aY as aY2, aZ as aZ2, a_ as a_2, a$ as a$2, b0 as b02, b1 as b12, b2 as b22, b3 as b32, b4 as b42, b5 as b52, b6 as b62, b7 as b72, b8 as b82, b9 as b92, ba as ba2, bb as bb2, bc as bc2, bd as bd2, be as be2, bf as bf2, bg as bg2, bh as bh2, bi as bi2, bj as bj2, bk as bk2, bl as bl2, bm as bm2, bn as bn2, bo as bo2, bp as bp2, bq as bq2, br as br2, bs as bs2, bt as bt2, bu as bu2, bv as bv2, bw as bw2, bx as bx2, by as by2, bz as bz2, bA as bA2, bB as bB2, bC as bC2, bD as bD2, bE as bE2, bF as bF2, bG as bG2, bH as bH2, bI as bI2, bJ as bJ2, bK as bK2, bL as bL2, bM as bM2, bN as bN2, bO as bO2, bP as bP2, bQ as bQ2, bR as bR2, bS as bS2, bT as bT2, bU as bU2, bV as bV2, bW as bW2, bX as bX2, bY as bY2, bZ as bZ2, b_ as b_2, b$ as b$2, c0 as c02, c1 as c12, c2 as c22, c3 as c32, c4 as c42, c5 as c52, c6 as c62, c7 as c72, c8 as c82, c9 as c92, ca as ca2, cb as cb2, cc as cc2, cd as cd2, ce as ce2, cf as cf2, cg as cg2, ch as ch2, ci as ci2, cj as cj2, ck as ck2, cl as cl2, cm as cm2, cn as cn2, co as co2, cp as cp2, cq as cq2, cr as cr2, cs as cs2, ct as ct2, cu as cu2, cv as cv2, cw as cw2, cx as cx2, cy as cy2, cz as cz2, cA as cA2, cB as cB2, cC as cC2, cD as cD2, cE as cE2, cF as cF2, cG, cH, cI, cJ, cK, cL, cM, cN, cO, cP, cQ, cR, cS, cT, cU, cV, cW, cX, cY, cZ, c_, c$, d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn, dp, dq, dr, ds, dt, du, dv, dw, dx, dy, dz, dA, dB, dC, dD, dE, dF, dG, dH, dI, dJ, dK, dL, dM, dN, dO, dP, dQ, dR, dS, dT, dU, dV, dW, dX, dY, dZ, d_, d$, e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en, eo, ep, eq, er, es, et, eu, ev, ew, ex, ey, ez, eA, eB, eC, eD, eE, eF, eG } from "./repo-source-CEBBBtm1.js";
|
|
5
5
|
const issueKey$1 = (i) => `${i.code}|${i.path ?? ""}|${i.mode ?? ""}|${i.code === "file-problem" ? i.message : ""}`;
|
|
6
6
|
const modeName = (mode) => mode === SINGLE_MODE ? "all modes" : modeDisplayName(mode);
|
|
7
7
|
const isPalette = (t2) => t2.tier === "brand" && t2.path.startsWith("palette.");
|
|
@@ -1023,6 +1023,16 @@ async function branchPreviewUrls(gh, ref, config, opts = {}) {
|
|
|
1023
1023
|
]);
|
|
1024
1024
|
return resolveBranchPreviews(apps, { branch: branch ?? "", ...pr !== void 0 ? { pr } : {}, ...sha ? { sha } : {} }, { comments, statuses, deployments });
|
|
1025
1025
|
}
|
|
1026
|
+
async function productPreviewOnGitHub(gh, product, e) {
|
|
1027
|
+
if (!product.preview) return null;
|
|
1028
|
+
const [comments, statuses, deployments] = await Promise.all([
|
|
1029
|
+
gh.listIssueComments(e.number).catch(() => []),
|
|
1030
|
+
e.sha ? gh.listCommitStatuses(e.sha).catch(() => []) : Promise.resolve([]),
|
|
1031
|
+
e.sha ? gh.listDeployments(e.sha).catch(() => []) : Promise.resolve([])
|
|
1032
|
+
]);
|
|
1033
|
+
const p2 = resolveBranchPreviews({ admin: product.preview }, { branch: e.branch, pr: e.number, ...e.sha ? { sha: e.sha } : {} }, { comments, statuses, deployments })[0];
|
|
1034
|
+
return p2 ? { ...p2, app: product.key, label: product.name } : null;
|
|
1035
|
+
}
|
|
1026
1036
|
const STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
|
|
1027
1037
|
const LIGHTNESS = { 50: 0.975, 100: 0.952, 200: 0.912, 300: 0.85, 400: 0.735, 500: 0.63, 600: 0.53, 700: 0.445, 800: 0.36, 900: 0.27, 950: 0.205 };
|
|
1028
1038
|
const BELL = { 50: 0.12, 100: 0.22, 200: 0.4, 300: 0.62, 400: 0.85, 500: 1, 600: 1, 700: 0.92, 800: 0.8, 900: 0.62, 950: 0.5 };
|
|
@@ -2112,7 +2122,7 @@ class DraftPoller {
|
|
|
2112
2122
|
function productPreview(apps, ctx, sources) {
|
|
2113
2123
|
if (!apps.admin || ctx.fromFork) return null;
|
|
2114
2124
|
const admin = resolveBranchPreviews(apps, { branch: ctx.branch, pr: ctx.pr, sha: ctx.sha }, sources).find((p2) => p2.app === "admin");
|
|
2115
|
-
if (!admin?.url || admin.source === "template" || admin.state === "failed") return null;
|
|
2125
|
+
if (!admin?.url || admin.source === "template" || admin.state === "failed" || admin.skipped) return null;
|
|
2116
2126
|
return admin.url;
|
|
2117
2127
|
}
|
|
2118
2128
|
function tryInProductUrl(preview, pr, screen) {
|
|
@@ -2135,6 +2145,7 @@ function localTryCommand(branch) {
|
|
|
2135
2145
|
const name = /^[\w./-]+$/.test(branch) ? branch : `'${branch.replace(/'/g, `'\\''`)}'`;
|
|
2136
2146
|
return `git fetch origin && git switch ${name}`;
|
|
2137
2147
|
}
|
|
2148
|
+
const explorationStartMessage = (e) => [`chore(explore): start ${e.name.trim()}`, ...e.purpose?.trim() ? [e.purpose.trim()] : [], "Exploration: never merged as is. Promote it to review or close it."].join("\n\n");
|
|
2138
2149
|
function explorationSummary(p2, _owner, _repo, s) {
|
|
2139
2150
|
const e = parseExplorationBody(p2.body);
|
|
2140
2151
|
const slug2 = p2.headRef?.startsWith(EXPLORATION_PREFIX) ? p2.headRef.slice(EXPLORATION_PREFIX.length) : e?.slug ?? explorationSlug(p2.title);
|
|
@@ -2146,7 +2157,8 @@ function explorationSummary(p2, _owner, _repo, s) {
|
|
|
2146
2157
|
name: e?.name ?? p2.title.replace(/^[A-Z][A-Z0-9_]*-\d+\s+/, "").replace(/^Exploration:\s*/i, ""),
|
|
2147
2158
|
purpose: e?.purpose ?? "",
|
|
2148
2159
|
...e?.useCase ? { useCase: e.useCase } : {},
|
|
2149
|
-
status: explorationStatus({ state: p2.state, labels: p2.labels, headRef: p2.headRef, body: p2.body }),
|
|
2160
|
+
status: explorationStatus({ state: p2.state, labels: p2.labels, headRef: p2.headRef, body: p2.body, headSha: p2.headSha, draft: p2.draft }),
|
|
2161
|
+
archived: isArchivedExploration(p2.labels),
|
|
2150
2162
|
draft: p2.draft,
|
|
2151
2163
|
author: e?.author ?? p2.author,
|
|
2152
2164
|
...e?.source ? { source: e.source } : {},
|
|
@@ -2158,7 +2170,28 @@ function explorationSummary(p2, _owner, _repo, s) {
|
|
|
2158
2170
|
}
|
|
2159
2171
|
async function listExplorationsOnGitHub(gh, s, opts = {}) {
|
|
2160
2172
|
const pulls = await gh.listPullRequests(opts.state ?? "open");
|
|
2161
|
-
|
|
2173
|
+
const archived = opts.archived ?? "exclude";
|
|
2174
|
+
return pulls.filter((p2) => isExplorationPull({ state: p2.state, labels: p2.labels, headRef: p2.headRef, body: p2.body })).filter((p2) => archived === "include" || archived === "only" === isArchivedExploration(p2.labels)).map((p2) => explorationSummary(p2, gh.owner, gh.name, s));
|
|
2175
|
+
}
|
|
2176
|
+
const isHiddenRepoError = (err) => err instanceof GitHubError && (err.status === 404 || err.status === 409 || err.status === 403 && err.auth !== "rejected" && !err.resetsAt);
|
|
2177
|
+
async function listProductExplorationsOnGitHub(clientFor, products, designSystemRepo, opts = {}) {
|
|
2178
|
+
const unreachable = [];
|
|
2179
|
+
const lists = await Promise.all(
|
|
2180
|
+
productRepos(products, designSystemRepo).map(async ({ product, repo }) => {
|
|
2181
|
+
try {
|
|
2182
|
+
const list = await listExplorationsOnGitHub(clientFor(repo), { packages: [], apps: {} }, opts);
|
|
2183
|
+
return list.map((x) => inProductRepo(x, product, repo));
|
|
2184
|
+
} catch (err) {
|
|
2185
|
+
unreachable.push({ product: product.key, name: product.name, repo, reason: isHiddenRepoError(err) ? "not-connected" : "unavailable" });
|
|
2186
|
+
return [];
|
|
2187
|
+
}
|
|
2188
|
+
})
|
|
2189
|
+
);
|
|
2190
|
+
return { explorations: lists.flat(), unreachable };
|
|
2191
|
+
}
|
|
2192
|
+
function inProductRepo(x, product, repo) {
|
|
2193
|
+
const url = previewUrl(product.preview, { branch: x.branch, pr: x.number, sha: x.headSha });
|
|
2194
|
+
return { ...x, repo, product: product.key, previews: url ? [{ app: product.key, label: product.name, url }] : [] };
|
|
2162
2195
|
}
|
|
2163
2196
|
async function startExplorationOnGitHub(gh, e, s) {
|
|
2164
2197
|
const problems = explorationProblems(e);
|
|
@@ -2172,14 +2205,10 @@ async function startExplorationOnGitHub(gh, e, s) {
|
|
|
2172
2205
|
const commit = await x.commitToNewBranch({
|
|
2173
2206
|
base: s.base,
|
|
2174
2207
|
branch,
|
|
2175
|
-
message:
|
|
2176
|
-
|
|
2177
|
-
${full.purpose.trim()}
|
|
2178
|
-
|
|
2179
|
-
Exploration: never merged as is. Promote it to review or close it.`,
|
|
2208
|
+
message: explorationStartMessage(full),
|
|
2180
2209
|
files: [{ path: explorationNotePath(slug2), content: explorationNote(full) }]
|
|
2181
2210
|
});
|
|
2182
|
-
const ctx = { owner: gh.owner, repo: gh.name, packages: s.packages, apps: s.apps, ...s.requests?.length ? { requests: s.requests } : {} };
|
|
2211
|
+
const ctx = { owner: gh.owner, repo: gh.name, packages: s.packages, apps: s.apps, ...s.requests?.length ? { requests: s.requests } : {}, ...s.inProduct ? { inProduct: s.inProduct } : {} };
|
|
2183
2212
|
const title = full.jira ? `${full.jira.trim().toUpperCase()} ${explorationPrTitle(full)}` : explorationPrTitle(full);
|
|
2184
2213
|
const pr = await x.createPullRequest({ title, head: branch, base: s.base, body: explorationPrBody(full, ctx), draft: true });
|
|
2185
2214
|
await x.addLabels(pr.number, [EXPLORATION_LABEL, ...s.labels ?? []]);
|
|
@@ -2194,6 +2223,16 @@ Exploration: never merged as is. Promote it to review or close it.`,
|
|
|
2194
2223
|
previews: previewLinks(s.apps, { branch, pr: pr.number, sha: commit.sha })
|
|
2195
2224
|
};
|
|
2196
2225
|
}
|
|
2226
|
+
async function productRepoAccess(gh) {
|
|
2227
|
+
try {
|
|
2228
|
+
const r = await gh.getRepo();
|
|
2229
|
+
if (r.permissions && r.permissions.push === false) return { ok: false, reason: "read-only" };
|
|
2230
|
+
return { ok: true, base: r.defaultBranch };
|
|
2231
|
+
} catch (err) {
|
|
2232
|
+
if (err instanceof GitHubError && (err.status === 404 || err.status === 403 && err.auth !== "rejected" && !err.resetsAt)) return { ok: false, reason: "not-connected" };
|
|
2233
|
+
throw err;
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2197
2236
|
async function explorationTryItOnGitHub(gh, e) {
|
|
2198
2237
|
const [comments, head] = await Promise.all([gh.listIssueComments(e.number), gh.getBranchSha(e.branch).catch(() => void 0)]);
|
|
2199
2238
|
return explorationTryIt({ comment: findPreviewComment(comments)?.body, headSha: head });
|
|
@@ -2241,12 +2280,470 @@ async function promoteExplorationOnGitHub(gh, ref, opts = {}) {
|
|
|
2241
2280
|
});
|
|
2242
2281
|
return out;
|
|
2243
2282
|
}
|
|
2283
|
+
async function archiveExplorationOnGitHub(gh, ref, opts = {}) {
|
|
2284
|
+
if (!gh.canWrite) throw new GitHubError(401, "Archiving an exploration needs a GitHub token (pull requests or issues: write).");
|
|
2285
|
+
const p2 = await findExplorationOnGitHub(gh, ref);
|
|
2286
|
+
if (p2.state !== "open") throw new GitHubError(422, `#${p2.number} is ${p2.state === "merged" ? "shipped" : "closed"}: only an open exploration is archived. Its link already stays on GitHub.`);
|
|
2287
|
+
const archived = opts.archived ?? true;
|
|
2288
|
+
if (archived) await gh.addLabels(p2.number, [EXPLORATION_ARCHIVED_LABEL]);
|
|
2289
|
+
else
|
|
2290
|
+
await gh.removeLabel(p2.number, EXPLORATION_ARCHIVED_LABEL).catch((e) => {
|
|
2291
|
+
if (!(e instanceof GitHubError && e.status === 404)) throw e;
|
|
2292
|
+
});
|
|
2293
|
+
return { number: p2.number, url: p2.url, branch: p2.headRef, archived };
|
|
2294
|
+
}
|
|
2244
2295
|
async function closeExplorationOnGitHub(gh, ref) {
|
|
2245
2296
|
if (!gh.canWrite) throw new GitHubError(401, "Closing an exploration needs a GitHub token (pull requests: write).");
|
|
2246
2297
|
const p2 = await findExplorationOnGitHub(gh, ref);
|
|
2247
2298
|
await gh.updatePullRequest(p2.number, { state: "closed" });
|
|
2248
2299
|
return { number: p2.number, url: p2.url, branch: p2.headRef };
|
|
2249
2300
|
}
|
|
2301
|
+
const PRODUCT_FILE = /\.(css|scss|sass|less|tsx|jsx|ts|js|mjs|cjs|mts|cts|astro|vue|svelte)$/;
|
|
2302
|
+
const SKIP_FILE = /\.d\.[cm]?ts$|\.(test|spec|stories|story)\.[cm]?[jt]sx?$|\.min\.(css|js)$/;
|
|
2303
|
+
const PIECES_FILE_LIMIT = 40;
|
|
2304
|
+
const cleanPath = (p2) => p2.trim().replace(/^\.?\/+|\/+$/g, "");
|
|
2305
|
+
function ownProduct(products, repo) {
|
|
2306
|
+
const p2 = repo ? productOfRepo(products, repo) : void 0;
|
|
2307
|
+
return p2 && p2.key !== defaultProduct(products).key ? p2 : void 0;
|
|
2308
|
+
}
|
|
2309
|
+
const repoOfProductBranch = (gh, lib) => lib && lib.fullName.toLowerCase() !== gh.fullName.toLowerCase() ? gh.fullName : void 0;
|
|
2310
|
+
function productOf(products, pull, files, repo) {
|
|
2311
|
+
const own = ownProduct(products, repo);
|
|
2312
|
+
if (own) return own;
|
|
2313
|
+
const product = productOfBranch(products, { labels: pull.labels, files });
|
|
2314
|
+
if (product.key === defaultProduct(products).key) throw new GitHubError(422, `This branch is a library branch (${product.name}), not a product branch: missing pieces are checked on a branch started for a product.`);
|
|
2315
|
+
return product;
|
|
2316
|
+
}
|
|
2317
|
+
async function readProductBranchOnGitHub(gh, pr, opts) {
|
|
2318
|
+
const pull = await gh.getPullRequest(pr);
|
|
2319
|
+
const cmp = await gh.compareDetailed(pull.baseRef, pull.headSha);
|
|
2320
|
+
const product = productOf(opts.products, pull, cmp.files.map((f) => f.filename), gh.fullName);
|
|
2321
|
+
const dir = product.path && !ownProduct(opts.products, gh.fullName) ? `${cleanPath(product.path)}/` : "";
|
|
2322
|
+
const changed = cmp.files.filter((f) => f.status !== "removed" && (!dir || f.filename.startsWith(dir)) && PRODUCT_FILE.test(f.filename) && !SKIP_FILE.test(f.filename) && !f.filename.split("/").includes("node_modules"));
|
|
2323
|
+
const read = changed.slice(0, PIECES_FILE_LIMIT);
|
|
2324
|
+
const start = cmp.mergeBase ?? pull.baseRef;
|
|
2325
|
+
const files = await Promise.all(
|
|
2326
|
+
read.map(async (f) => {
|
|
2327
|
+
const [before, after] = await Promise.all([f.status === "added" ? Promise.resolve(void 0) : gh.getFileText(f.previous_filename ?? f.filename, start), gh.getFileText(f.filename, pull.headSha)]);
|
|
2328
|
+
return { path: f.filename, before: before ?? null, after: after ?? null };
|
|
2329
|
+
})
|
|
2330
|
+
);
|
|
2331
|
+
return { pull, product, files, skipped: changed.length - read.length, record: parsePiecesRecord(pull.body) };
|
|
2332
|
+
}
|
|
2333
|
+
async function recordPiecesOnGitHub(gh, pr, check) {
|
|
2334
|
+
const pull = await gh.getPullRequest(pr);
|
|
2335
|
+
const record = mergePiecesRecord(parsePiecesRecord(pull.body), { checkedAt: check.checkedAt ?? (/* @__PURE__ */ new Date()).toISOString(), headSha: check.headSha ?? pull.headSha, pieces: check.pieces, fixes: check.fixes });
|
|
2336
|
+
await gh.updatePullRequest(pr, { body: withPiecesRecord(pull.body, record) });
|
|
2337
|
+
return record;
|
|
2338
|
+
}
|
|
2339
|
+
const productWriter = (gh, branch) => isExplorationBranch(branch) ? gh.withBranchPrefix(EXPLORATION_PREFIX) : gh;
|
|
2340
|
+
async function useLibraryPreviewOnGitHub(gh, input) {
|
|
2341
|
+
const message = `chore(bridge): use the preview of ${input.libraryBranch} (#${input.libraryNumber})
|
|
2342
|
+
|
|
2343
|
+
The product branch takes the library branch before it ships. Switch to the published version once it does.`;
|
|
2344
|
+
try {
|
|
2345
|
+
const r = await productWriter(gh, input.productBranch).mergeIntoBranch(input.productBranch, input.libraryBranch, message);
|
|
2346
|
+
return { ...r, said: r.status === "merged" ? "Your branch now uses the preview of the library branch." : "Your branch already has the latest preview." };
|
|
2347
|
+
} catch (err) {
|
|
2348
|
+
if (err instanceof GitHubError && err.status === 409) return { status: "conflict", sha: null, said: `Your branch and the library branch change the same lines. A developer merges ${input.libraryBranch} into ${input.productBranch} by hand.` };
|
|
2349
|
+
throw err;
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
function productBranchRef(pull, product, repo) {
|
|
2353
|
+
const name = /<!-- bridge-exploration (\{[\s\S]*?\}) -->/.exec(pull.body ?? "");
|
|
2354
|
+
let title = pull.title.replace(/^[A-Z][A-Z0-9_]*-\d+\s+/, "").replace(/^Exploration:\s*/i, "");
|
|
2355
|
+
let author = pull.author;
|
|
2356
|
+
if (name) {
|
|
2357
|
+
try {
|
|
2358
|
+
const e = JSON.parse(name[1]);
|
|
2359
|
+
if (e.name) title = e.name;
|
|
2360
|
+
if (e.author) author = e.author;
|
|
2361
|
+
} catch {
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
return { pr: pull.number, title: title.charAt(0).toUpperCase() + title.slice(1), branch: pull.headRef, url: pull.url, productKey: product.key, productName: product.name, ...author ? { author } : {}, ...repo ? { repo } : {} };
|
|
2365
|
+
}
|
|
2366
|
+
async function openLibraryBranchOnGitHub(gh, input) {
|
|
2367
|
+
const pull = await gh.getPullRequest(input.pr);
|
|
2368
|
+
const record = parsePiecesRecord(pull.body);
|
|
2369
|
+
const piece = record?.pieces.find((p2) => p2.id === input.piece);
|
|
2370
|
+
if (!record || !piece) throw new GitHubError(404, record ? `No piece "${input.piece}" on #${input.pr}. Pieces: ${record.pieces.map((p2) => p2.id).join(", ") || "none"}.` : `#${input.pr} was not checked yet: find its missing pieces first (bridge_missing_pieces with record, or \`bridge pieces ${input.pr} --record\`).`);
|
|
2371
|
+
const product = productOf(input.products, pull, await gh.listPullRequestFiles(input.pr).then((f) => f.map((x) => x.filename), () => []), gh.fullName);
|
|
2372
|
+
const mode = input.mode ?? "direct";
|
|
2373
|
+
const lib = input.library ?? gh;
|
|
2374
|
+
const repo = repoOfProductBranch(gh, input.library);
|
|
2375
|
+
const plan = libraryBranchPlan(piece, productBranchRef(pull, product, repo), { source: input.source, requestedBy: input.openedBy, mode });
|
|
2376
|
+
const existing = record.links.find((l) => l.piece === piece.id);
|
|
2377
|
+
if (existing) return { status: "already-linked", plan, link: existing, preview: null, warnings: [] };
|
|
2378
|
+
if (input.dryRun) return { status: "dry-run", plan, link: null, preview: null, warnings: [] };
|
|
2379
|
+
if (!gh.canWrite || !lib.canWrite) throw new GitHubError(401, mode === "suggest" ? "Suggesting a library change needs a GitHub token (issues: write)." : "Opening a library branch needs a GitHub token (contents, pull requests and issues: write).");
|
|
2380
|
+
const warnings = [];
|
|
2381
|
+
const at2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
2382
|
+
const who = { ...input.openedBy ? { openedBy: input.openedBy } : {}, ...input.agent ? { agent: input.agent } : {}, ...repo ? { repo: lib.fullName } : {} };
|
|
2383
|
+
let link;
|
|
2384
|
+
if (plan.kind === "token-change") {
|
|
2385
|
+
if (!input.writeTokens) throw new GitHubError(422, "This piece is a token: open it where the token files are read (Bridge Studio, bridge_open_library_branch or `bridge pieces open`).");
|
|
2386
|
+
const r = await input.writeTokens(plan, { mode });
|
|
2387
|
+
link = r.status === "suggested" ? { piece: piece.id, kind: "suggestion", number: r.number, url: r.url, title: plan.title, at: at2, ...who } : { piece: piece.id, kind: "token-change", number: r.number, url: r.url, title: plan.title, branch: r.branch, at: at2, ...who };
|
|
2388
|
+
} else if (plan.kind === "exploration") {
|
|
2389
|
+
const r = await startExplorationOnGitHub(lib, { ...plan.exploration, ...input.openedBy ? { author: input.openedBy } : {}, ...input.agent ? { agent: input.agent } : {} }, { base: input.base, ...input.exploration, labels: [NEEDED_BY_LABEL] });
|
|
2390
|
+
link = { piece: piece.id, kind: "exploration", number: r.pr, url: r.url, title: plan.title, branch: r.branch, at: at2, ...who };
|
|
2391
|
+
} else {
|
|
2392
|
+
const issue = composeRequestIssue(plan.request, { labels: [NEEDED_BY_LABEL] });
|
|
2393
|
+
const r = await lib.createIssue(issue);
|
|
2394
|
+
link = { piece: piece.id, kind: "request", number: r.number, url: r.url, title: plan.title, at: at2, ...who };
|
|
2395
|
+
}
|
|
2396
|
+
try {
|
|
2397
|
+
if (link.kind === "request" || link.kind === "suggestion") {
|
|
2398
|
+
const issue = await lib.getIssue(link.number);
|
|
2399
|
+
await lib.updateIssue(link.number, { body: withNeededBy(issue.body, plan.neededBy) });
|
|
2400
|
+
if (link.kind === "suggestion" && !issue.labels.includes(NEEDED_BY_LABEL)) await lib.addLabels(link.number, [NEEDED_BY_LABEL]);
|
|
2401
|
+
} else {
|
|
2402
|
+
const libPull = await lib.getPullRequest(link.number);
|
|
2403
|
+
await lib.updatePullRequest(link.number, { body: withNeededBy(libPull.body, plan.neededBy) });
|
|
2404
|
+
await lib.addLabels(link.number, [NEEDED_BY_LABEL]);
|
|
2405
|
+
}
|
|
2406
|
+
} catch (err) {
|
|
2407
|
+
if (err instanceof GitHubError && err.auth === "rejected") throw err;
|
|
2408
|
+
warnings.push(`The library side does not say who needs it yet (${err.message}). Add "Needed by ${repo ?? ""}#${input.pr}" to #${link.number} on GitHub.`);
|
|
2409
|
+
}
|
|
2410
|
+
try {
|
|
2411
|
+
const fresh = await gh.getPullRequest(input.pr);
|
|
2412
|
+
const next = withLink(parsePiecesRecord(fresh.body) ?? record, link);
|
|
2413
|
+
await gh.updatePullRequest(input.pr, { body: withPiecesRecord(fresh.body, next) });
|
|
2414
|
+
} catch (err) {
|
|
2415
|
+
if (mode !== "suggest") throw err;
|
|
2416
|
+
warnings.push(`#${input.pr} does not list #${link.number} yet (${err.message}). Add "Library: ${repo ? lib.fullName : ""}#${link.number}" to #${input.pr} on GitHub, so this piece is not sent twice.`);
|
|
2417
|
+
}
|
|
2418
|
+
let preview = null;
|
|
2419
|
+
if (!repo && (input.usePreview ?? true) && link.kind === "token-change" && link.branch) {
|
|
2420
|
+
preview = await useLibraryPreviewOnGitHub(gh, { productBranch: pull.headRef, libraryBranch: link.branch, libraryNumber: link.number }).catch((err) => {
|
|
2421
|
+
warnings.push(`Your branch does not use the preview yet: ${err.message}`);
|
|
2422
|
+
return null;
|
|
2423
|
+
});
|
|
2424
|
+
}
|
|
2425
|
+
return { status: link.kind === "suggestion" ? "suggested" : "opened", plan, link, preview, warnings };
|
|
2426
|
+
}
|
|
2427
|
+
function acrossRepos(p2, lifecycle, across) {
|
|
2428
|
+
if (!across || !p2.action) return p2;
|
|
2429
|
+
if (lifecycle === "merged") return { ...p2, sentence: "The library published it. Update @bridge-ds/react in your product to use it.", action: null };
|
|
2430
|
+
return { ...p2, action: null };
|
|
2431
|
+
}
|
|
2432
|
+
const isNote = (path) => path.startsWith(`${EXPLORATION_NOTES_DIR}/`);
|
|
2433
|
+
async function linkedLibraryBranchOnGitHub(gh, link, product, piece, opts = {}) {
|
|
2434
|
+
const nearest = piece?.nearest?.label;
|
|
2435
|
+
const behind = () => opts.across ? Promise.resolve(null) : gh.compare(product.baseRef, product.headSha).then((c) => c.behindBy, () => null);
|
|
2436
|
+
if (link.kind === "suggestion") {
|
|
2437
|
+
const issue = await gh.getIssue(link.number);
|
|
2438
|
+
const cached = suggestionStateFromLabels(issue.labels);
|
|
2439
|
+
const s = suggestionStatus({ state: issue.state, stateReason: issue.stateReason, applied: cached === "applying", review: cached === "applying" ? void 0 : cached });
|
|
2440
|
+
const status2 = linkStatus({ kind: "suggestion", status: s });
|
|
2441
|
+
const lifecycle2 = s === "applied" ? "merged" : issue.state === "closed" ? "closed" : "open";
|
|
2442
|
+
const behindMain2 = lifecycle2 === "merged" ? await behind() : null;
|
|
2443
|
+
const preview2 = libraryPreviewState({ kind: "suggestion", lifecycle: lifecycle2, hasChanges: false, missing: null, total: null, behindMain: behindMain2, nearest });
|
|
2444
|
+
return { link, piece, status: status2, preview: acrossRepos(preview2, lifecycle2, opts.across), people: status2.people };
|
|
2445
|
+
}
|
|
2446
|
+
if (link.kind === "request") {
|
|
2447
|
+
const issue = await gh.getIssue(link.number);
|
|
2448
|
+
const status2 = linkStatus({ kind: "request", state: issue.state, stateReason: issue.stateReason });
|
|
2449
|
+
const lifecycle2 = issue.state === "closed" ? issue.stateReason === "not_planned" ? "closed" : "merged" : "open";
|
|
2450
|
+
const behindMain2 = lifecycle2 === "merged" ? await behind() : null;
|
|
2451
|
+
const preview2 = libraryPreviewState({ kind: "request", lifecycle: lifecycle2, hasChanges: false, missing: null, total: null, behindMain: behindMain2, nearest });
|
|
2452
|
+
return { link, piece, status: status2, preview: acrossRepos(preview2, lifecycle2, opts.across), people: status2.people };
|
|
2453
|
+
}
|
|
2454
|
+
const lib = await gh.getPullRequest(link.number);
|
|
2455
|
+
const reviews = await gh.listReviews(link.number).catch(() => []);
|
|
2456
|
+
const status = linkStatus({ kind: link.kind, state: lib.state, draft: lib.draft, labels: lib.labels, requestedReviewers: lib.requestedReviewers, reviews: reviews.map((r) => ({ user: r.user, state: r.state })) });
|
|
2457
|
+
const lifecycle = lib.state === "merged" ? "merged" : lib.state === "open" ? "open" : "closed";
|
|
2458
|
+
let missing = null;
|
|
2459
|
+
let total = null;
|
|
2460
|
+
let behindMain = null;
|
|
2461
|
+
let hasChanges = true;
|
|
2462
|
+
if (lifecycle === "open") {
|
|
2463
|
+
const [files, own, inProduct] = await Promise.all([
|
|
2464
|
+
gh.listPullRequestFiles(link.number).catch(() => null),
|
|
2465
|
+
gh.compare(lib.baseRef, lib.headSha).catch(() => null),
|
|
2466
|
+
opts.across ? Promise.resolve(null) : gh.compare(product.headSha, lib.headSha).catch(() => null)
|
|
2467
|
+
]);
|
|
2468
|
+
hasChanges = files ? files.some((f) => !isNote(f.filename)) : true;
|
|
2469
|
+
total = own?.aheadBy ?? null;
|
|
2470
|
+
missing = inProduct?.aheadBy ?? null;
|
|
2471
|
+
} else if (lifecycle === "merged") {
|
|
2472
|
+
behindMain = await behind();
|
|
2473
|
+
}
|
|
2474
|
+
const preview = libraryPreviewState({ kind: link.kind, lifecycle, hasChanges, missing, total, behindMain, nearest });
|
|
2475
|
+
return { link, piece, status, preview: acrossRepos(preview, lifecycle, opts.across), people: status.people };
|
|
2476
|
+
}
|
|
2477
|
+
async function productBranchViewOnGitHub(gh, pr, opts) {
|
|
2478
|
+
const pull = await gh.getPullRequest(pr);
|
|
2479
|
+
const files = await gh.listPullRequestFiles(pr).then((f) => f.map((x) => x.filename), () => []);
|
|
2480
|
+
const product = productOf(opts.products, pull, files, gh.fullName);
|
|
2481
|
+
const record = parsePiecesRecord(pull.body);
|
|
2482
|
+
const across = Boolean(repoOfProductBranch(gh, opts.library));
|
|
2483
|
+
const lib = opts.library ?? gh;
|
|
2484
|
+
const linked = await Promise.all(
|
|
2485
|
+
(record?.links ?? []).map((l) => linkedLibraryBranchOnGitHub(lib, l, { headSha: pull.headSha, baseRef: pull.baseRef }, record?.pieces.find((p2) => p2.id === l.piece), { across }))
|
|
2486
|
+
);
|
|
2487
|
+
const open = (record?.pieces ?? []).filter((p2) => !record.links.some((l) => l.piece === p2.id));
|
|
2488
|
+
return { pull, product, record, sentence: productBranchSentence(record, { viewer: opts.viewer, agentName: opts.agentName }), linked, open };
|
|
2489
|
+
}
|
|
2490
|
+
async function switchToPublishedOnGitHub(gh, pr) {
|
|
2491
|
+
if (!gh.canWrite) throw new GitHubError(401, "Switching needs a GitHub token (contents and pull requests: write).");
|
|
2492
|
+
const pull = await gh.getPullRequest(pr);
|
|
2493
|
+
if (pull.state !== "open") throw new GitHubError(422, `#${pr} is ${pull.state}: only an open branch switches.`);
|
|
2494
|
+
const cmp = await gh.compare(pull.baseRef, pull.headSha);
|
|
2495
|
+
if (cmp.behindBy === 0) return { status: "up-to-date", said: "Your branch already uses the published version." };
|
|
2496
|
+
try {
|
|
2497
|
+
await gh.updatePullRequestBranch(pr, pull.headSha);
|
|
2498
|
+
} catch (err) {
|
|
2499
|
+
if (err instanceof GitHubError && err.status === 422) throw new GitHubError(422, `Your branch and ${pull.baseRef} change the same lines, so Bridge cannot switch it alone. Use "Update from main" to pick the token values, or ask a developer.`, err.detail);
|
|
2500
|
+
throw err;
|
|
2501
|
+
}
|
|
2502
|
+
return { status: "switched", said: `Your branch now uses the published version from ${pull.baseRef}.` };
|
|
2503
|
+
}
|
|
2504
|
+
async function proposePiecesOnGitHub(gh, pr, input) {
|
|
2505
|
+
const out = { proposed: [], already: [], unknown: [], warnings: [] };
|
|
2506
|
+
const ids = [...new Set(input.pieces.map((p2) => p2.trim()).filter(Boolean))];
|
|
2507
|
+
if (!ids.length) return out;
|
|
2508
|
+
const pull = await gh.getPullRequest(pr);
|
|
2509
|
+
const record = parsePiecesRecord(pull.body);
|
|
2510
|
+
if (!record) throw new GitHubError(404, `#${pr} was not checked against the library yet: find its missing pieces first (bridge_missing_pieces with record, or \`bridge pieces ${pr} --record\`).`);
|
|
2511
|
+
const files = await gh.listPullRequestFiles(pr).then((f) => f.map((x) => x.filename), () => []);
|
|
2512
|
+
const lib = input.library ?? gh;
|
|
2513
|
+
const repo = repoOfProductBranch(gh, input.library);
|
|
2514
|
+
const ref = productBranchRef(pull, ownProduct(input.products, repo) ?? productOfBranch(input.products, { labels: pull.labels, files }), repo);
|
|
2515
|
+
const todo = [];
|
|
2516
|
+
for (const id of ids) {
|
|
2517
|
+
const piece = record.pieces.find((p2) => p2.id === id);
|
|
2518
|
+
const link = record.links.find((l) => l.piece === id);
|
|
2519
|
+
if (!piece) out.unknown.push(id);
|
|
2520
|
+
else if (link) out.already.push({ piece: id, number: link.number });
|
|
2521
|
+
else todo.push({ piece, ask: pieceRequest(piece, ref, { previewUrl: input.previewUrl, source: input.source, requestedBy: input.openedBy }) });
|
|
2522
|
+
}
|
|
2523
|
+
if (input.dryRun) return { ...out, proposed: todo.map((t2) => ({ piece: t2.piece.id, title: t2.ask.request.title, number: 0, url: "" })) };
|
|
2524
|
+
if (!todo.length) return out;
|
|
2525
|
+
if (!lib.canWrite) throw new GitHubError(401, "Sending pieces to the library needs a GitHub token (issues: write).");
|
|
2526
|
+
const at2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
2527
|
+
const who = { ...input.openedBy ? { openedBy: input.openedBy } : {}, ...input.agent ? { agent: input.agent } : {}, ...repo ? { repo: lib.fullName } : {} };
|
|
2528
|
+
const links = [];
|
|
2529
|
+
for (const t2 of todo) {
|
|
2530
|
+
const issue = composeRequestIssue(t2.ask.request, { labels: [NEEDED_BY_LABEL] });
|
|
2531
|
+
const r = await lib.createIssue({ ...issue, body: withNeededBy(issue.body, t2.ask.neededBy) });
|
|
2532
|
+
links.push({ piece: t2.piece.id, kind: "request", number: r.number, url: r.url, title: t2.ask.request.title, at: at2, ...who });
|
|
2533
|
+
out.proposed.push({ piece: t2.piece.id, title: t2.ask.request.title, number: r.number, url: r.url });
|
|
2534
|
+
}
|
|
2535
|
+
try {
|
|
2536
|
+
const fresh = await gh.getPullRequest(pr);
|
|
2537
|
+
const next = links.reduce((rec, l) => withLink(rec, l), parsePiecesRecord(fresh.body) ?? record);
|
|
2538
|
+
await gh.updatePullRequest(pr, { body: withPiecesRecord(fresh.body, next) });
|
|
2539
|
+
} catch (err) {
|
|
2540
|
+
if (err instanceof GitHubError && err.auth === "rejected") throw err;
|
|
2541
|
+
out.warnings.push(`#${pr} does not list the requests yet (${err.message}). Add "Library: ${links.map((l) => `${repo ? lib.fullName : ""}#${l.number}`).join(", ")}" to #${pr} on GitHub, so they are not sent twice.`);
|
|
2542
|
+
}
|
|
2543
|
+
return out;
|
|
2544
|
+
}
|
|
2545
|
+
async function doneExploringOnGitHub(gh, ref, input = {}) {
|
|
2546
|
+
const p2 = await findExplorationOnGitHub(gh, ref);
|
|
2547
|
+
const status = explorationStatus({ state: p2.state, labels: p2.labels, headRef: p2.headRef, body: p2.body, headSha: p2.headSha, draft: p2.draft });
|
|
2548
|
+
if (status === "closed") throw new GitHubError(422, `Exploration #${p2.number} is closed. Reopen it on GitHub first: its preview comes back with it.`);
|
|
2549
|
+
if (status === "shipped") throw new GitHubError(422, `#${p2.number} is already shipped.`);
|
|
2550
|
+
if (status === "promoted") throw new GitHubError(422, `#${p2.number} was already sent to review.`);
|
|
2551
|
+
const fresh = status === "active";
|
|
2552
|
+
const files = fresh ? await gh.listPullRequestFiles(p2.number) : [];
|
|
2553
|
+
const plan = fresh ? doneExploringPlan({ body: p2.body, branch: p2.headRef, files: files.map((f) => ({ path: f.filename, status: f.status })), date: input.date }) : null;
|
|
2554
|
+
const take = plan?.take ?? ["git fetch origin", `git checkout ${p2.headRef}`];
|
|
2555
|
+
const checks = p2.headSha ? await Promise.resolve(p2.headSha).then((sha) => gh.getChecks(sha)).then((c) => c.state, () => null) : null;
|
|
2556
|
+
const out = { number: p2.number, url: p2.url, branch: p2.headRef, status: fresh ? "ready" : status, handedOff: fresh, plan, pieces: { proposed: [], already: [], unknown: [], warnings: [] }, take, checks, note: explorationStartingPoint(checks), warnings: [] };
|
|
2557
|
+
const products = input.products ?? [];
|
|
2558
|
+
const ask = { pieces: input.pieces ?? [], products, previewUrl: input.previewUrl, openedBy: input.openedBy, agent: input.agent, source: input.source, library: input.library };
|
|
2559
|
+
if (input.dryRun) {
|
|
2560
|
+
out.pieces = await proposePiecesOnGitHub(gh, p2.number, { ...ask, dryRun: true }).catch((e) => ({ proposed: [], already: [], unknown: [], warnings: [e.message] }));
|
|
2561
|
+
return out;
|
|
2562
|
+
}
|
|
2563
|
+
if (!gh.canWrite) throw new GitHubError(401, 'Saying "Done exploring" needs a GitHub token (contents, pull requests and issues: write).');
|
|
2564
|
+
out.pieces = await proposePiecesOnGitHub(gh, p2.number, ask);
|
|
2565
|
+
out.warnings.push(...out.pieces.warnings);
|
|
2566
|
+
if (!plan) return out;
|
|
2567
|
+
const x = gh.withBranchPrefix(EXPLORATION_PREFIX);
|
|
2568
|
+
let doneSha = p2.headSha;
|
|
2569
|
+
if (plan.removeFiles.length) {
|
|
2570
|
+
const c = await x.commitToBranch({ branch: p2.headRef, message: "chore(explore): done exploring, remove the exploration note", files: plan.removeFiles.map((path) => ({ path, content: null })) }).catch((e) => {
|
|
2571
|
+
if (e instanceof GitHubError && e.auth === "rejected") throw e;
|
|
2572
|
+
out.warnings.push(`The exploration note stays on the branch (${e.message}). Delete ${plan.removeFiles.join(", ")} before merging.`);
|
|
2573
|
+
return null;
|
|
2574
|
+
});
|
|
2575
|
+
if (c) doneSha = c.sha;
|
|
2576
|
+
}
|
|
2577
|
+
await x.addLabels(p2.number, plan.addLabels);
|
|
2578
|
+
await x.removeLabel(p2.number, plan.removeLabels[0]).catch((e) => {
|
|
2579
|
+
if (!(e instanceof GitHubError && e.status === 404)) out.warnings.push(`The exploration label is still on (${e.message}). Remove it on GitHub so developers can ship it later.`);
|
|
2580
|
+
});
|
|
2581
|
+
const latest = await gh.getPullRequest(p2.number).catch(() => p2);
|
|
2582
|
+
const doneAt = parseExplorationBody(plan.body)?.doneAt ?? (input.date ?? /* @__PURE__ */ new Date()).toISOString();
|
|
2583
|
+
await x.updatePullRequest(p2.number, { body: withDoneExploring(latest.body, { branch: p2.headRef, doneAt, doneSha, checks }) });
|
|
2584
|
+
return out;
|
|
2585
|
+
}
|
|
2586
|
+
const CONTINUE_PHRASE = "Continue Bridge exploration";
|
|
2587
|
+
const onlyNotes = (files) => Boolean(files?.length) && files.every((f) => f.startsWith(".bridge/"));
|
|
2588
|
+
function explorationStage(x) {
|
|
2589
|
+
if (x.status !== "active" || x.archived) return "handed";
|
|
2590
|
+
if (x.files && (x.files.length === 0 || onlyNotes(x.files))) return "not-started";
|
|
2591
|
+
return "exploring";
|
|
2592
|
+
}
|
|
2593
|
+
const continueRef = (x) => explorationRefLabel(x);
|
|
2594
|
+
function continueLines(x) {
|
|
2595
|
+
const ref = continueRef(x);
|
|
2596
|
+
const name = x.name.replace(/"/g, "'").trim();
|
|
2597
|
+
return {
|
|
2598
|
+
app: `${CONTINUE_PHRASE} ${ref} "${name}" in ${x.productName} and use the Bridge library.`,
|
|
2599
|
+
terminal: `claude "${CONTINUE_PHRASE} ${ref}"`
|
|
2600
|
+
};
|
|
2601
|
+
}
|
|
2602
|
+
function parseContinueLine(text) {
|
|
2603
|
+
const m = /continue\s+bridge\s+exploration\s+((?:[a-z0-9][\w.-]*)?#\d+)/i.exec(text);
|
|
2604
|
+
return m ? m[1].toLowerCase() : null;
|
|
2605
|
+
}
|
|
2606
|
+
function wordsOf(name) {
|
|
2607
|
+
const spaced = name.replace(/[-_]+/g, " ").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([a-z0-9])([A-Z])/g, "$1 $2").trim();
|
|
2608
|
+
const words = spaced.split(/\s+/).filter(Boolean);
|
|
2609
|
+
return words.map((w, i) => i === 0 ? w.charAt(0).toUpperCase() + w.slice(1) : /^[A-Z]{2,}$/.test(w) ? w : w.toLowerCase()).join(" ");
|
|
2610
|
+
}
|
|
2611
|
+
const SKIP$1 = [/^\.bridge\//, /^\.changeset\//, /^\.github\//, /\.(test|spec|stories)\.[jt]sx?$/, /\.d\.ts$/, /(^|\/)package(-lock)?\.json$/, /\.md$/, /(^|\/)__snapshots__\//, /\.docs\.json$/];
|
|
2612
|
+
const CODE = /\.(tsx|jsx|ts|js|vue|svelte|astro|css|scss)$/;
|
|
2613
|
+
const SCREEN_DIRS = /(^|\/)(pages|routes|screens|views|app)\//;
|
|
2614
|
+
function thingOf(path) {
|
|
2615
|
+
if (SKIP$1.some((r) => r.test(path))) return null;
|
|
2616
|
+
if (/(^|\/)tokens\/src\//.test(path) || /\.tokens\.json$/.test(path)) return "Tokens";
|
|
2617
|
+
if (!CODE.test(path)) return null;
|
|
2618
|
+
const parts = path.split("/");
|
|
2619
|
+
const file = parts[parts.length - 1];
|
|
2620
|
+
const base = file.replace(/\.module\.(css|scss)$/, "").replace(/\.[^.]+$/, "");
|
|
2621
|
+
const ci3 = parts.lastIndexOf("components");
|
|
2622
|
+
if (ci3 >= 0 && ci3 < parts.length - 2 && /^[A-Z]/.test(parts[ci3 + 1])) return wordsOf(parts[ci3 + 1]);
|
|
2623
|
+
if (/^[A-Z][A-Za-z0-9]+$/.test(base)) return wordsOf(base);
|
|
2624
|
+
if (SCREEN_DIRS.test(path)) {
|
|
2625
|
+
const name = base === "index" || base === "page" ? parts[parts.length - 2] : base;
|
|
2626
|
+
if (name && !/^\[/.test(name) && !["pages", "routes", "screens", "views", "app", "src"].includes(name)) return `${wordsOf(name)} screen`;
|
|
2627
|
+
}
|
|
2628
|
+
return null;
|
|
2629
|
+
}
|
|
2630
|
+
function changedThings(files) {
|
|
2631
|
+
const out = [];
|
|
2632
|
+
for (const f of files) {
|
|
2633
|
+
const t2 = thingOf(f);
|
|
2634
|
+
if (t2 && !out.includes(t2)) out.push(t2);
|
|
2635
|
+
}
|
|
2636
|
+
return out;
|
|
2637
|
+
}
|
|
2638
|
+
function listThings(things, max = 2) {
|
|
2639
|
+
if (things.length <= max) return things.length === 2 ? `${things[0]} and ${things[1]}` : things[0] ?? "";
|
|
2640
|
+
return `${things.slice(0, max).join(", ")} and ${things.length - max} more`;
|
|
2641
|
+
}
|
|
2642
|
+
const PAST = {
|
|
2643
|
+
add: "added",
|
|
2644
|
+
build: "built",
|
|
2645
|
+
change: "changed",
|
|
2646
|
+
drop: "dropped",
|
|
2647
|
+
fix: "fixed",
|
|
2648
|
+
make: "made",
|
|
2649
|
+
move: "moved",
|
|
2650
|
+
polish: "polished",
|
|
2651
|
+
remove: "removed",
|
|
2652
|
+
rename: "renamed",
|
|
2653
|
+
replace: "replaced",
|
|
2654
|
+
rework: "reworked",
|
|
2655
|
+
set: "set",
|
|
2656
|
+
show: "showed",
|
|
2657
|
+
split: "split",
|
|
2658
|
+
swap: "swapped",
|
|
2659
|
+
try: "tried",
|
|
2660
|
+
tweak: "tweaked",
|
|
2661
|
+
update: "updated",
|
|
2662
|
+
use: "used",
|
|
2663
|
+
wire: "wired"
|
|
2664
|
+
};
|
|
2665
|
+
function isClaudeAssisted(c) {
|
|
2666
|
+
const m = c.commit.message;
|
|
2667
|
+
return /co-authored-by:\s*claude/i.test(m) || /generated with \[?claude/i.test(m);
|
|
2668
|
+
}
|
|
2669
|
+
const isClaudeAccount = (c) => /claude/i.test(c.author?.login ?? "") || /^claude\b/i.test(c.commit.author?.name ?? "");
|
|
2670
|
+
const isBot = (name) => /\[bot\]$|^github-actions\b|-bot$/i.test(name);
|
|
2671
|
+
function humanAuthorOf(c) {
|
|
2672
|
+
if (isClaudeAccount(c)) return null;
|
|
2673
|
+
const login = c.author?.login?.trim();
|
|
2674
|
+
if (login) return isBot(login) ? null : login;
|
|
2675
|
+
const name = c.commit.author?.name?.trim();
|
|
2676
|
+
return name && !isBot(name) ? name : null;
|
|
2677
|
+
}
|
|
2678
|
+
function isClaudeCommit(c) {
|
|
2679
|
+
return isClaudeAccount(c) || isClaudeAssisted(c) && !humanAuthorOf(c);
|
|
2680
|
+
}
|
|
2681
|
+
const isStartCommit = (c) => /^chore\(explore\): start /.test(c.commit.message);
|
|
2682
|
+
function subjectWords(subject) {
|
|
2683
|
+
const s = subject.replace(/^[a-z]+(\([^)]*\))?!?:\s*/i, "").replace(/\s*—\s*/g, ", ").replace(/\s*\(#\d+\)\s*$/, "").trim();
|
|
2684
|
+
if (!s) return "made a change";
|
|
2685
|
+
const [first2, ...rest] = s.split(/\s+/);
|
|
2686
|
+
const past = PAST[first2.toLowerCase()];
|
|
2687
|
+
if (past) return [past, ...rest].join(" ");
|
|
2688
|
+
if (/^(added|built|changed|fixed|made|moved|removed|renamed|replaced|updated|used|tried|swapped|tweaked)$/i.test(first2)) return [first2.toLowerCase(), ...rest].join(" ");
|
|
2689
|
+
return `changed ${/^[A-Z][a-z]/.test(s) ? s.charAt(0).toLowerCase() + s.slice(1) : s}`;
|
|
2690
|
+
}
|
|
2691
|
+
const dateOf = (c) => c.commit.author?.date ?? c.commit.committer?.date ?? "";
|
|
2692
|
+
function explorationActivity(input) {
|
|
2693
|
+
const commits = input.commits.filter((c) => !isStartCommit(c));
|
|
2694
|
+
const events = commits.map((c) => {
|
|
2695
|
+
const claude = isClaudeCommit(c);
|
|
2696
|
+
const withClaude = !claude && isClaudeAssisted(c);
|
|
2697
|
+
const who = claude ? "claude" : humanAuthorOf(c) ?? input.author;
|
|
2698
|
+
return { who, claude, ...withClaude ? { withClaude } : {}, text: subjectWords(c.commit.message.split("\n")[0]), at: dateOf(c), sha: c.sha };
|
|
2699
|
+
}).sort((a2, b) => b.at.localeCompare(a2.at));
|
|
2700
|
+
const start = input.commits.find(isStartCommit);
|
|
2701
|
+
const startedAt = input.startedAt ?? (start ? dateOf(start) : null);
|
|
2702
|
+
if (startedAt) events.push({ who: input.author, claude: false, text: "started the exploration", at: startedAt });
|
|
2703
|
+
return events.slice(0, input.limit ?? events.length);
|
|
2704
|
+
}
|
|
2705
|
+
function lastActivity(input) {
|
|
2706
|
+
const latest = explorationActivity({ commits: input.commits, author: input.author }).find((e) => e.text !== "started the exploration");
|
|
2707
|
+
if (!latest) return null;
|
|
2708
|
+
const things = changedThings(input.files ?? []);
|
|
2709
|
+
return { who: latest.who, claude: latest.claude, ...latest.withClaude ? { withClaude: true } : {}, text: things.length ? `changed ${listThings(things)}` : latest.text, at: latest.at };
|
|
2710
|
+
}
|
|
2711
|
+
function shortAgo(iso, now = /* @__PURE__ */ new Date()) {
|
|
2712
|
+
const t2 = new Date(iso).getTime();
|
|
2713
|
+
if (!Number.isFinite(t2)) return "";
|
|
2714
|
+
const s = Math.max(0, (now.getTime() - t2) / 1e3);
|
|
2715
|
+
if (s < 60) return "just now";
|
|
2716
|
+
if (s < 3600) return `${Math.round(s / 60)} min ago`;
|
|
2717
|
+
if (s < 86400) return `${Math.round(s / 3600)} h ago`;
|
|
2718
|
+
const days = Math.floor(s / 86400);
|
|
2719
|
+
if (days === 1) return "Yesterday";
|
|
2720
|
+
if (days < 7) return `${days} days ago`;
|
|
2721
|
+
return new Date(t2).toLocaleDateString("en", { month: "short", day: "numeric", ...new Date(t2).getFullYear() !== now.getFullYear() ? { year: "numeric" } : {} });
|
|
2722
|
+
}
|
|
2723
|
+
function startedWhen(iso, now = /* @__PURE__ */ new Date()) {
|
|
2724
|
+
const t2 = new Date(iso);
|
|
2725
|
+
if (!Number.isFinite(t2.getTime())) return "";
|
|
2726
|
+
const day = (d) => Math.floor(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()) / 864e5);
|
|
2727
|
+
const diff = day(now) - day(t2);
|
|
2728
|
+
if (diff <= 0) return "today";
|
|
2729
|
+
if (diff === 1) return "yesterday";
|
|
2730
|
+
if (diff < 7) return `${diff} days ago`;
|
|
2731
|
+
return t2.toLocaleDateString("en", { month: "short", day: "numeric", ...t2.getFullYear() !== now.getFullYear() ? { year: "numeric" } : {} });
|
|
2732
|
+
}
|
|
2733
|
+
function actorName(e, names2) {
|
|
2734
|
+
if (e.claude) return "Claude";
|
|
2735
|
+
const n = names2?.[e.who] ?? e.who;
|
|
2736
|
+
return e.withClaude ? `${n} with Claude` : n;
|
|
2737
|
+
}
|
|
2738
|
+
function whereItStands(input) {
|
|
2739
|
+
if (input.stage === "not-started") return `"${input.name}" is started but nothing is built yet.`;
|
|
2740
|
+
if (input.stage === "handed") return `"${input.name}" is ${input.statusLabel ? input.statusLabel.toLowerCase() : "with the developers"}.`;
|
|
2741
|
+
const things = changedThings(input.files ?? []);
|
|
2742
|
+
const latest = input.events.find((e) => e.text !== "started the exploration");
|
|
2743
|
+
const who = (e) => actorName(e, input.names);
|
|
2744
|
+
const so = things.length ? `So far it changes ${listThings(things, 3)}.` : "Something changed already.";
|
|
2745
|
+
return latest ? `${so} Last: ${who(latest)} ${latest.text}, ${shortAgo(latest.at, input.now).toLowerCase()}.` : so;
|
|
2746
|
+
}
|
|
2250
2747
|
const hex2 = (x) => Math.round(Math.max(0, Math.min(255, x))).toString(16).padStart(2, "0");
|
|
2251
2748
|
function rgbOf(v) {
|
|
2252
2749
|
const m = /^rgba?\(([^)]*)\)$/i.exec(v.trim());
|
|
@@ -3043,7 +3540,7 @@ function locate(parentBuilt, parentMeasured, axis, built, measured, builtParts,
|
|
|
3043
3540
|
if (!stacked) {
|
|
3044
3541
|
const tallest = [...kids].sort((a2, b) => b.m[len] - a2.m[len])[0];
|
|
3045
3542
|
const change = tallest.b[len] - tallest.m[len];
|
|
3046
|
-
if (Math.abs(change) >= 1) out.push(...
|
|
3543
|
+
if (Math.abs(change) >= 1) out.push(...ownSize2(tallest, change));
|
|
3047
3544
|
return out;
|
|
3048
3545
|
}
|
|
3049
3546
|
let prevB = pb[axis];
|
|
@@ -3052,13 +3549,13 @@ function locate(parentBuilt, parentMeasured, axis, built, measured, builtParts,
|
|
|
3052
3549
|
const gap = k.b[axis] - prevB - (k.m[axis] - prevM);
|
|
3053
3550
|
say(gap, i === 0 ? `${before} the ${partWords(k.p)}` : `${after} the ${partWords(kids[i - 1].p)}`);
|
|
3054
3551
|
const change = k.b[len] - k.m[len];
|
|
3055
|
-
if (Math.abs(change) >= 1) out.push(...
|
|
3552
|
+
if (Math.abs(change) >= 1) out.push(...ownSize2(k, change));
|
|
3056
3553
|
prevB = k.b[axis] + k.b[len];
|
|
3057
3554
|
prevM = k.m[axis] + k.m[len];
|
|
3058
3555
|
});
|
|
3059
3556
|
say(pb[axis] + pb[len] - prevB - (pm[axis] + pm[len] - prevM), `${after} the ${partWords(kids.at(-1).p)}`);
|
|
3060
3557
|
return out;
|
|
3061
|
-
function
|
|
3558
|
+
function ownSize2(k, change) {
|
|
3062
3559
|
const inner = depth < 3 ? locate(k.p.id, pairs.get(k.p.id), axis, built, measured, builtParts, pairs, depth + 1) : [];
|
|
3063
3560
|
if (inner.length) return inner;
|
|
3064
3561
|
return [{ amount: change, text: `the ${partWords(k.p)} is ${round$1(Math.abs(change))} px ${change < 0 ? axis === "y" ? "shorter" : "narrower" : axis === "y" ? "taller" : "wider"} in Figma` }];
|
|
@@ -3163,12 +3660,16 @@ function buildGapCase(input) {
|
|
|
3163
3660
|
const checkedVariants = [];
|
|
3164
3661
|
const specVariant = new Map((spec?.variants ?? []).map((v) => [variantKeyOf(v.props), v]));
|
|
3165
3662
|
if (input.fidelity) {
|
|
3166
|
-
for (const r of input.fidelity.variants)
|
|
3663
|
+
for (const r of input.fidelity.variants) {
|
|
3664
|
+
if (r.status === "skipped") continue;
|
|
3665
|
+
const variant = matchVariant(spec, propsOfKey(r.key));
|
|
3666
|
+
checkedVariants.push({ key: r.key, props: variant?.props ?? propsOfKey(r.key), result: r, variant });
|
|
3667
|
+
}
|
|
3167
3668
|
} else for (const [key2, v] of specVariant) checkedVariants.push({ key: key2, props: v.props, variant: v });
|
|
3168
3669
|
const variants = [];
|
|
3169
3670
|
for (const cv3 of checkedVariants) {
|
|
3170
3671
|
if (cv3.result && cv3.result.status !== "differs") continue;
|
|
3171
|
-
const shot = input.shots?.[cv3.key];
|
|
3672
|
+
const shot = input.shots?.[cv3.key] ?? (cv3.variant ? input.shots?.[variantKeyOf(cv3.variant.props)] : void 0);
|
|
3172
3673
|
const story = spec ? storyForVariant(spec, cv3.props, stories, shot) : shot ? stories.find((s) => s.shot?.file === shot.file) : void 0;
|
|
3173
3674
|
const gv = {
|
|
3174
3675
|
key: cv3.key,
|
|
@@ -3257,744 +3758,803 @@ function gapDetail(component, variants, checked, referee) {
|
|
|
3257
3758
|
}
|
|
3258
3759
|
return lines.join("\n");
|
|
3259
3760
|
}
|
|
3260
|
-
const
|
|
3261
|
-
const
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3761
|
+
const NOT_AN_AXIS = /^(as|asChild|render|component|className|class|style|id|key|ref|role|type|name|form|dir|lang|tabIndex|slot|children|htmlFor|value|defaultValue|placeholder|href|target|rel|src|alt)$/i;
|
|
3762
|
+
const STATE_PROPS = /* @__PURE__ */ new Set(["disabled", "checked", "indeterminate"]);
|
|
3763
|
+
const STATES$1 = [
|
|
3764
|
+
{ value: "Default", of: (s) => !s.state && s.props?.disabled !== true },
|
|
3765
|
+
{ value: "Hover", of: (s) => s.state === "hover" && s.props?.disabled !== true },
|
|
3766
|
+
{ value: "Pressed", of: (s) => s.state === "active" && s.props?.disabled !== true },
|
|
3767
|
+
{ value: "Focus", of: (s) => s.state === "focus-visible" && s.props?.disabled !== true },
|
|
3768
|
+
{ value: "Disabled", of: (s) => s.props?.disabled === true }
|
|
3769
|
+
];
|
|
3770
|
+
const setNameOf$2 = (title) => title.split("/").at(-1).trim();
|
|
3771
|
+
const axisName = (prop) => prop.charAt(0).toUpperCase() + prop.slice(1).replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase();
|
|
3772
|
+
const propsOf$1 = (s) => ({ ...s.props ?? {}, ...s.overrides ?? {} });
|
|
3773
|
+
function checkedOf(s) {
|
|
3774
|
+
const p2 = propsOf$1(s);
|
|
3775
|
+
return p2.indeterminate === true ? "mixed" : String(p2.checked === true);
|
|
3776
|
+
}
|
|
3777
|
+
const LITERAL_FIELDS = ["fill", "textFill", "stroke", "fontFamily", "shadow"];
|
|
3778
|
+
function valuesOf(spec, partId, hasChildren, known, fills = false, own = { width: true, height: true }) {
|
|
3779
|
+
const sized = { ...hasChildren ? boxSized(spec, partId, own) : {}, ...spec.sized?.[partId] };
|
|
3780
|
+
const v = { ...spec.values[partId] ?? {} };
|
|
3781
|
+
const raw = spec.raw[partId] ?? {};
|
|
3782
|
+
for (const field of Object.keys(v)) {
|
|
3783
|
+
const value = v[field];
|
|
3784
|
+
if (typeof value !== "string" || value.startsWith("calc(") || known(value)) continue;
|
|
3785
|
+
const literal = raw[field];
|
|
3786
|
+
if (literal === void 0) delete v[field];
|
|
3787
|
+
else v[field] = literal;
|
|
3266
3788
|
}
|
|
3267
|
-
|
|
3789
|
+
for (const field of LITERAL_FIELDS) if (v[field] === void 0 && typeof raw[field] === "string") v[field] = raw[field];
|
|
3790
|
+
if (hasChildren) {
|
|
3791
|
+
if (typeof v.width === "number" && !fills) delete v.width;
|
|
3792
|
+
if (typeof v.height === "number") delete v.height;
|
|
3793
|
+
}
|
|
3794
|
+
if (sized?.width !== void 0) v.width = sized.width;
|
|
3795
|
+
if (sized?.height !== void 0) v.height = sized.height;
|
|
3796
|
+
return v;
|
|
3268
3797
|
}
|
|
3269
|
-
|
|
3270
|
-
const
|
|
3271
|
-
const
|
|
3272
|
-
|
|
3273
|
-
const
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
const
|
|
3280
|
-
const
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
if (!isObj$3(w)) return at2("where must be an object with args and/or state");
|
|
3284
|
-
for (const k of Object.keys(w)) if (k !== "args" && k !== "state") at2(`where.${k} is not known (args, state)`);
|
|
3285
|
-
if (w.args !== void 0 && (!isObj$3(w.args) || !Object.values(w.args).every(plain))) at2("where.args maps arg names to a text, number or true/false");
|
|
3286
|
-
if (w.state !== void 0 && !STATES$1.includes(w.state)) at2(`where.state is one of ${STATES$1.join(", ")}`);
|
|
3287
|
-
}
|
|
3288
|
-
function validateFigmaFixes(data) {
|
|
3289
|
-
const out = [];
|
|
3290
|
-
if (!isObj$3(data)) return ["expected an object with version and fixes"];
|
|
3291
|
-
if (data.version !== FIGMA_FIXES_VERSION) out.push(`version ${String(data.version)} is not supported (expected ${FIGMA_FIXES_VERSION})`);
|
|
3292
|
-
for (const k of Object.keys(data)) if (!["$schema", "version", "fixes"].includes(k)) out.push(`${k} is not known (version, fixes)`);
|
|
3293
|
-
if (!Array.isArray(data.fixes)) return [...out, "fixes must be a list"];
|
|
3294
|
-
const ids = /* @__PURE__ */ new Set();
|
|
3295
|
-
data.fixes.forEach((f, i) => {
|
|
3296
|
-
const label = isObj$3(f) && typeof f.id === "string" ? `fix ${f.id}` : `fix ${i + 1}`;
|
|
3297
|
-
const at2 = (why) => out.push(`${label}: ${why}`);
|
|
3298
|
-
if (!isObj$3(f)) return at2("must be an object");
|
|
3299
|
-
if (typeof f.id !== "string" || !/^[a-z0-9][a-z0-9-]{0,79}$/.test(f.id)) at2("id must be lower case letters, digits and dashes");
|
|
3300
|
-
else if (ids.has(f.id)) at2("id is repeated");
|
|
3301
|
-
else ids.add(f.id);
|
|
3302
|
-
if (typeof f.component !== "string" || !f.component.trim()) at2('component is missing (the Figma set name, like "Toggle")');
|
|
3303
|
-
if (typeof f.reason !== "string" || f.reason.trim().length < 8) at2("reason is missing: say why, in a sentence");
|
|
3304
|
-
else if (/\u2014/.test(f.reason)) at2("reason uses an em dash: use a colon or a comma");
|
|
3305
|
-
if (f.by !== void 0 && typeof f.by !== "string") at2("by must be a text");
|
|
3306
|
-
if (f.where !== void 0) whereProblems(f.where, at2);
|
|
3307
|
-
if (!KINDS.includes(f.kind)) return at2(`kind must be one of ${KINDS.join(", ")}`);
|
|
3308
|
-
const kind = f.kind;
|
|
3309
|
-
for (const k of Object.keys(f)) if (!BASE_KEYS.includes(k) && !KEYS[kind].includes(k)) at2(`${k} is not a key of a ${kind} fix`);
|
|
3310
|
-
if (kind === "part") partProblems(f, at2);
|
|
3311
|
-
if (kind === "axis") axisProblems(f, at2);
|
|
3312
|
-
if (kind === "story") {
|
|
3313
|
-
const u = f.use;
|
|
3314
|
-
if (!isObj$3(u) || typeof u.story !== "string" || !u.story) at2("use.story is the story id to draw the variant from");
|
|
3315
|
-
else {
|
|
3316
|
-
for (const k of Object.keys(u)) if (!["story", "args", "state"].includes(k)) at2(`use.${k} is not known (story, args, state)`);
|
|
3317
|
-
if (u.args !== void 0 && (!isObj$3(u.args) || !Object.values(u.args).every(plain))) at2("use.args maps arg names to a text, number or true/false");
|
|
3318
|
-
if (u.state !== void 0 && !STATES$1.includes(u.state)) at2(`use.state is one of ${STATES$1.join(", ")}`);
|
|
3319
|
-
}
|
|
3320
|
-
if (!isObj$3(f.where) || !f.where.args && !f.where.state) at2("where names the variant (args and/or state) the story is for");
|
|
3321
|
-
}
|
|
3322
|
-
if (kind === "status") {
|
|
3323
|
-
if (f.status === "matches") at2('status cannot be "matches": only the shot comparison says a component matches');
|
|
3324
|
-
else if (f.status !== void 0 && f.status !== "differs" && f.status !== "cant-check") at2("status is differs or cant-check (absent: a note)");
|
|
3325
|
-
}
|
|
3326
|
-
});
|
|
3798
|
+
function boxSized(spec, partId, own) {
|
|
3799
|
+
const box = spec.boxes?.[partId];
|
|
3800
|
+
const kids = spec.parts.filter((c) => c.parent === partId && !c.pin && !c.cover && !c.overlay).map((c) => spec.boxes?.[c.id]).filter((b) => !!b);
|
|
3801
|
+
if (!box || !kids.length) return {};
|
|
3802
|
+
const raw = spec.raw[partId] ?? {};
|
|
3803
|
+
const num = (f) => typeof raw[f] === "number" ? raw[f] : 0;
|
|
3804
|
+
const left = Math.min(...kids.map((k) => k.x));
|
|
3805
|
+
const top = Math.min(...kids.map((k) => k.y));
|
|
3806
|
+
const side = (f) => typeof raw[f] === "number" ? raw[f] : num("strokeWeight");
|
|
3807
|
+
const contentW = Math.max(...kids.map((k) => k.x + k.width)) - left + num("paddingLeft") + num("paddingRight") + side("strokeLeftWeight") + side("strokeRightWeight");
|
|
3808
|
+
const contentH = Math.max(...kids.map((k) => k.y + k.height)) - top + num("paddingTop") + num("paddingBottom") + side("strokeTopWeight") + side("strokeBottomWeight");
|
|
3809
|
+
const out = {};
|
|
3810
|
+
if (own.width && box.width - contentW > 1) out.width = box.width;
|
|
3811
|
+
if (own.height && box.height - contentH > 1) out.height = box.height;
|
|
3327
3812
|
return out;
|
|
3328
3813
|
}
|
|
3329
|
-
function
|
|
3330
|
-
|
|
3331
|
-
const
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
else if (!Number.isFinite(value)) at2(`set.${field} must be a finite number`);
|
|
3351
|
-
} else if (typeof value !== "string" || !value.trim()) at2(`set.${field} must be a token path, a number or null`);
|
|
3352
|
-
else if (field === "textDecoration" && !/^(UNDERLINE|STRIKETHROUGH|NONE)$/.test(value)) at2(`set.textDecoration is UNDERLINE, STRIKETHROUGH or NONE`);
|
|
3353
|
-
}
|
|
3814
|
+
function setOf(name, stories, argTypes, source, known, hints = {}) {
|
|
3815
|
+
const propName = (prop) => hints.properties?.[prop] ?? axisName(prop);
|
|
3816
|
+
const figmaValue = (prop, value) => hints.values?.[prop]?.[value] ?? value;
|
|
3817
|
+
const lead = stories.find((s) => s.name === "Default" && !s.state) ?? stories[0];
|
|
3818
|
+
const baseline = (k, a2) => (lead ? propsOf$1(lead)[k] : void 0) ?? a2.default ?? false;
|
|
3819
|
+
const shown = stories.filter((s) => !/skeleton/i.test(s.name));
|
|
3820
|
+
const ordered = [...shown.length ? shown : stories].sort((a2, b) => Number(!!a2.gallery) - Number(!!b.gallery));
|
|
3821
|
+
const valueOf = (s, k, a2) => (propsOf$1(s)[k] ?? a2.default ?? false) === true;
|
|
3822
|
+
const flags = Object.entries(argTypes).filter(
|
|
3823
|
+
([k, a2]) => a2.kind === "boolean" && !STATE_PROPS.has(k) && !NOT_AN_AXIS.test(k) && ordered.some((s) => valueOf(s, k, a2)) && ordered.some((s) => !valueOf(s, k, a2))
|
|
3824
|
+
);
|
|
3825
|
+
const plain2 = ordered.filter(
|
|
3826
|
+
(s) => Object.entries(argTypes).every(
|
|
3827
|
+
([k, a2]) => a2.kind !== "boolean" || STATE_PROPS.has(k) || NOT_AN_AXIS.test(k) || flags.some(([f]) => f === k) || (propsOf$1(s)[k] ?? a2.default ?? false) === baseline(k, a2)
|
|
3828
|
+
)
|
|
3829
|
+
);
|
|
3830
|
+
if (!plain2.length) return void 0;
|
|
3831
|
+
const axes = [];
|
|
3832
|
+
for (const [prop, a2] of flags) {
|
|
3833
|
+
const def = String(baseline(prop, a2) === true);
|
|
3834
|
+
axes.push({ name: propName(prop), prop, values: [figmaValue(prop, def), figmaValue(prop, def === "true" ? "false" : "true")], default: figmaValue(prop, def) });
|
|
3354
3835
|
}
|
|
3355
|
-
for (const
|
|
3356
|
-
|
|
3357
|
-
|
|
3836
|
+
for (const [prop, a2] of Object.entries(argTypes)) {
|
|
3837
|
+
if (a2.kind !== "enum" || NOT_AN_AXIS.test(prop) || !a2.options || a2.options.length < 2 || a2.options.length > 12) continue;
|
|
3838
|
+
const seen = new Set(plain2.map((s) => String(propsOf$1(s)[prop] ?? a2.default ?? a2.options[0])));
|
|
3839
|
+
const values = a2.options.filter((o) => seen.has(o));
|
|
3840
|
+
if (values.length < 2) continue;
|
|
3841
|
+
const def = a2.default !== void 0 && values.includes(String(a2.default)) ? String(a2.default) : values[0];
|
|
3842
|
+
axes.push({ name: propName(prop), prop, values: [...new Set(values.map((v) => figmaValue(prop, v)))], default: figmaValue(prop, def) });
|
|
3358
3843
|
}
|
|
3359
|
-
if (
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
if (!isObj$3(a2) || a2.primary === void 0 && a2.counter === void 0) at2("align gives primary and/or counter");
|
|
3363
|
-
else {
|
|
3364
|
-
if (a2.primary !== void 0 && !PRIMARY.includes(a2.primary)) at2(`align.primary is ${PRIMARY.join(", ")}`);
|
|
3365
|
-
if (a2.counter !== void 0 && !COUNTER.includes(a2.counter)) at2(`align.counter is ${COUNTER.join(", ")}`);
|
|
3366
|
-
}
|
|
3844
|
+
if ("checked" in argTypes || plain2.some((s) => "checked" in propsOf$1(s))) {
|
|
3845
|
+
const values = ["false", "true", "mixed"].filter((v) => plain2.some((s) => checkedOf(s) === v));
|
|
3846
|
+
if (values.length > 1) axes.push({ name: "Checked", values, default: values[0] });
|
|
3367
3847
|
}
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3848
|
+
const states = STATES$1.filter((st) => plain2.some(st.of)).map((st) => st.value);
|
|
3849
|
+
if (states.length > 1) axes.push({ name: "State", values: states, default: states[0] });
|
|
3850
|
+
const keyOf = (s) => {
|
|
3851
|
+
const props = {};
|
|
3852
|
+
for (const axis of axes) {
|
|
3853
|
+
const flag = flags.find(([k]) => k === axis.prop);
|
|
3854
|
+
const value = axis.name === "State" ? STATES$1.find((st) => st.of(s))?.value : axis.name === "Checked" ? checkedOf(s) : flag ? figmaValue(flag[0], String(valueOf(s, flag[0], flag[1]))) : propsOf$1(s)[axis.prop] === void 0 ? axis.default : figmaValue(axis.prop, String(propsOf$1(s)[axis.prop]));
|
|
3855
|
+
if (value === void 0 || !axis.values.includes(value)) return void 0;
|
|
3856
|
+
props[axis.name] = value;
|
|
3857
|
+
}
|
|
3858
|
+
return props;
|
|
3859
|
+
};
|
|
3860
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
3861
|
+
for (const s of plain2) {
|
|
3862
|
+
const props = keyOf(s);
|
|
3863
|
+
if (!props) continue;
|
|
3864
|
+
const k = JSON.stringify(props);
|
|
3865
|
+
if (!candidates.has(k)) candidates.set(k, { props, stories: [] });
|
|
3866
|
+
candidates.get(k).stories.push(s);
|
|
3371
3867
|
}
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
const
|
|
3384
|
-
if (
|
|
3868
|
+
const storyFor = /* @__PURE__ */ new Map();
|
|
3869
|
+
if (axes.some((a2) => a2.name === "State")) {
|
|
3870
|
+
const rest = (p2) => JSON.stringify(Object.entries(p2).filter(([k]) => k !== "State"));
|
|
3871
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3872
|
+
for (const c of candidates.values()) groups.set(rest(c.props), [...groups.get(rest(c.props)) ?? [], c]);
|
|
3873
|
+
for (const [key2, group] of groups) {
|
|
3874
|
+
const ids = [...new Set(group.flatMap((c) => c.stories.map((s) => s.id)))];
|
|
3875
|
+
const score = (id) => group.filter((c) => c.stories.some((s) => s.id === id)).length;
|
|
3876
|
+
storyFor.set(key2, ids.reduce((best, id) => score(id) > score(best) ? id : best, ids[0]));
|
|
3877
|
+
}
|
|
3878
|
+
for (const c of candidates.values()) {
|
|
3879
|
+
const same = c.stories.filter((s) => s.id === storyFor.get(rest(c.props)));
|
|
3880
|
+
if (same.length) c.stories = same;
|
|
3385
3881
|
}
|
|
3386
3882
|
}
|
|
3387
|
-
|
|
3388
|
-
if (
|
|
3389
|
-
|
|
3390
|
-
|
|
3883
|
+
const byVariant = new Map([...candidates].map(([k, c]) => [k, { props: c.props, story: c.stories[0] }]));
|
|
3884
|
+
if (!byVariant.size) return void 0;
|
|
3885
|
+
const isDefault = (p2) => axes.every((a2) => p2[a2.name] === a2.default);
|
|
3886
|
+
const base = [...byVariant.values()].find((v) => isDefault(v.props)) ?? [...byVariant.values()][0];
|
|
3887
|
+
const baseSpec = base.story.spec;
|
|
3888
|
+
const parts = baseSpec.parts.map((p2) => baseSpec.vectors?.[p2.id] ? { ...p2, kind: "vector" } : { ...p2 });
|
|
3889
|
+
for (const p2 of parts) {
|
|
3890
|
+
if (!p2.overlay || p2.pin || p2.cover) continue;
|
|
3891
|
+
const pin = pinFromBoxes(baseSpec, p2);
|
|
3892
|
+
if (pin) p2.pin = pin;
|
|
3893
|
+
else p2.cover = true;
|
|
3391
3894
|
}
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3895
|
+
const paints = (id) => {
|
|
3896
|
+
const v = baseSpec.values[id] ?? {};
|
|
3897
|
+
return [v.fill, v.stroke].some((x) => x !== void 0 && x !== null);
|
|
3898
|
+
};
|
|
3899
|
+
for (const p2 of [...parts].reverse()) {
|
|
3900
|
+
if (!p2.parent || p2.kind !== "frame" || p2.pin || p2.cover || p2.overlay || paints(p2.id)) continue;
|
|
3901
|
+
const kids = parts.filter((c) => c.parent === p2.id);
|
|
3902
|
+
if (kids.length && kids.every((c) => c.overlay || c.pin || c.cover)) p2.cover = true;
|
|
3903
|
+
}
|
|
3904
|
+
const aligners = new Set(
|
|
3905
|
+
parts.filter((p2) => {
|
|
3906
|
+
const flow = parts.filter((c) => c.parent === p2.id && !c.pin && !c.cover && !c.overlay);
|
|
3907
|
+
return flow.length === 1 && !!p2.layout?.align?.[flow[0].id];
|
|
3908
|
+
}).map((p2) => p2.id)
|
|
3909
|
+
);
|
|
3910
|
+
for (const p2 of parts) if (p2.layout) p2.layout = alignedLayout(p2, parts);
|
|
3911
|
+
const parents = new Set(parts.filter((p2) => !p2.pin && !p2.cover).map((p2) => p2.parent).filter(Boolean));
|
|
3912
|
+
const variants = [];
|
|
3913
|
+
const axesMemo = /* @__PURE__ */ new Map();
|
|
3914
|
+
const shotOf = /* @__PURE__ */ new Map();
|
|
3915
|
+
const spacersOf = /* @__PURE__ */ new Map();
|
|
3916
|
+
const wrapsOf = /* @__PURE__ */ new Map();
|
|
3917
|
+
for (const { props, story: story2 } of byVariant.values()) {
|
|
3918
|
+
const m = story2.spec;
|
|
3919
|
+
const pairs = story2 === base.story ? new Map(parts.map((p2) => [p2.id, p2.id])) : pairParts(baseSpec.parts, m);
|
|
3920
|
+
const values = {};
|
|
3921
|
+
const vectors = {};
|
|
3922
|
+
const pins = {};
|
|
3923
|
+
const hidden = [];
|
|
3924
|
+
const spacers = {};
|
|
3925
|
+
const wraps = {};
|
|
3926
|
+
const layouts = {};
|
|
3927
|
+
for (const p2 of parts) {
|
|
3928
|
+
const mid = pairs.get(p2.id);
|
|
3929
|
+
if (mid === void 0) {
|
|
3930
|
+
hidden.push(p2.id);
|
|
3931
|
+
continue;
|
|
3932
|
+
}
|
|
3933
|
+
values[p2.id] = valuesOf(m, mid, parents.has(p2.id) && !aligners.has(p2.id), known, !p2.parent && !!p2.fill, ownAxes(p2, parts, baseSpec, axesMemo));
|
|
3934
|
+
if (m.spacers?.[mid]) spacers[p2.id] = m.spacers[mid];
|
|
3935
|
+
if (p2.kind === "icon" || p2.kind === "vector") delete values[p2.id].fill;
|
|
3936
|
+
const mp = m.parts.find((x) => x.id === mid);
|
|
3937
|
+
const pin = mp?.pin ?? (mp?.overlay ? pinFromBoxes(m, mp) : void 0);
|
|
3938
|
+
if (p2.pin && pin && JSON.stringify(pin) !== JSON.stringify(p2.pin)) pins[p2.id] = pin;
|
|
3939
|
+
if (mp?.layout && p2.layout) {
|
|
3940
|
+
const layout = alignedLayout({ ...mp, id: p2.id }, m.parts.map((x) => ({ ...x, parent: x.parent === mid ? p2.id : x.parent })));
|
|
3941
|
+
if (layout && (layout.primary !== p2.layout.primary || layout.counter !== p2.layout.counter || layout.direction !== p2.layout.direction)) layouts[p2.id] = layout;
|
|
3942
|
+
}
|
|
3943
|
+
if (mp?.wrap) wraps[p2.id] = mp.wrap.padding;
|
|
3944
|
+
const vec = p2.kind === "vector" ? m.vectors?.[mid] : void 0;
|
|
3945
|
+
if (vec) vectors[p2.id] = { svg: vec.svg, strokes: vec.strokes.every((v) => typeof v !== "string" || known(v)) ? [...vec.strokes] : [] };
|
|
3400
3946
|
}
|
|
3947
|
+
const variant = { props, values, ...hidden.length ? { hidden } : {}, ...Object.keys(vectors).length ? { vectors } : {}, ...Object.keys(pins).length ? { pins } : {}, ...Object.keys(layouts).length ? { layout: layouts } : {} };
|
|
3948
|
+
variants.push(variant);
|
|
3949
|
+
spacersOf.set(variant, spacers);
|
|
3950
|
+
wrapsOf.set(variant, wraps);
|
|
3951
|
+
if (story2.shot) shotOf.set(variant, story2.shot);
|
|
3401
3952
|
}
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3953
|
+
textRootInFrame(parts, variants);
|
|
3954
|
+
spacerWrappers(parts, variants, spacersOf, wrapsOf);
|
|
3955
|
+
const properties = textProperties(parts, base.story, argTypes, new Set(axes.map((a2) => a2.name)));
|
|
3956
|
+
const kept = drawnAxes(axes, variants);
|
|
3957
|
+
const story = `${source.replace(/\/+$/, "")}/?path=/story/${base.story.id}`;
|
|
3958
|
+
const spec = { name, hash: "", source: [story], axes: kept.axes, properties, parts, variants: withoutIdleStates(kept.variants), unmapped: [] };
|
|
3959
|
+
const shots = {};
|
|
3960
|
+
kept.variants.forEach((v) => {
|
|
3961
|
+
const from = variants.find((x) => JSON.stringify(x.values) === JSON.stringify(v.values) && Object.entries(v.props).every(([k, val]) => x.props[k] === val));
|
|
3962
|
+
const shot = from && shotOf.get(from);
|
|
3963
|
+
if (shot) shots[variantKeyOf(v.props)] = shot;
|
|
3964
|
+
});
|
|
3965
|
+
return { spec: { ...spec, hash: hashSpec(spec) }, shots };
|
|
3405
3966
|
}
|
|
3406
|
-
const
|
|
3407
|
-
|
|
3408
|
-
const
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3967
|
+
const TEXT_FIELDS = /* @__PURE__ */ new Set(["textFill", "fontFamily", "fontSize", "fontWeight", "lineHeight", "letterSpacing", "textDecoration"]);
|
|
3968
|
+
function textRootInFrame(parts, variants) {
|
|
3969
|
+
const root = parts.find((p2) => !p2.parent);
|
|
3970
|
+
if (!root || root.kind !== "text") return;
|
|
3971
|
+
const id = `${root.id}-text`;
|
|
3972
|
+
const text = { ...root, id, name: `${root.name} text`, parent: root.id };
|
|
3973
|
+
parts.splice(parts.indexOf(root), 1, { id: root.id, name: root.name, kind: "frame", ...root.source ? { source: root.source } : {}, layout: { direction: "HORIZONTAL", primary: "MIN", counter: "MIN" } }, text);
|
|
3974
|
+
for (const v of variants) {
|
|
3975
|
+
const all = v.values[root.id] ?? {};
|
|
3976
|
+
v.values[root.id] = Object.fromEntries(Object.entries(all).filter(([f, value]) => !TEXT_FIELDS.has(f) && !((f === "width" || f === "height") && typeof value === "number")));
|
|
3977
|
+
v.values[id] = Object.fromEntries(Object.entries(all).filter(([f]) => TEXT_FIELDS.has(f)));
|
|
3978
|
+
if (v.hidden?.includes(root.id)) v.hidden.push(id);
|
|
3979
|
+
}
|
|
3416
3980
|
}
|
|
3417
|
-
function
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3981
|
+
function ownAxes(part, parts, spec, memo = /* @__PURE__ */ new Map()) {
|
|
3982
|
+
const parent = parts.find((x) => x.id === part.parent);
|
|
3983
|
+
const dir = parent?.layout?.direction;
|
|
3984
|
+
const stretch = parent?.layout?.counter === "STRETCH";
|
|
3985
|
+
const sizedBy = (axis) => !parent || !spec || definiteAxis(parent, axis, parts, spec, memo);
|
|
3986
|
+
const acrossW = dir === "VERTICAL" && stretch && sizedBy("width");
|
|
3987
|
+
const alongW = dir === "HORIZONTAL" && !!part.grow && sizedBy("width");
|
|
3988
|
+
const acrossH = dir === "HORIZONTAL" && stretch && sizedBy("height");
|
|
3989
|
+
const alongH = dir === "VERTICAL" && !!part.grow && sizedBy("height");
|
|
3990
|
+
return {
|
|
3991
|
+
width: !(!part.parent && part.fill) && !acrossW && !alongW && !part.stretch?.width,
|
|
3992
|
+
height: !acrossH && !alongH && !part.stretch?.height
|
|
3993
|
+
};
|
|
3994
|
+
}
|
|
3995
|
+
function definiteAxis(part, axis, parts, spec, memo) {
|
|
3996
|
+
const key2 = `${part.id}:${axis}`;
|
|
3997
|
+
const known = memo.get(key2);
|
|
3998
|
+
if (known !== void 0) return known;
|
|
3999
|
+
memo.set(key2, false);
|
|
4000
|
+
let result;
|
|
4001
|
+
if (!part.parent) result = axis === "width" && !!part.fill;
|
|
4002
|
+
else if (spec.sized?.[part.id]?.[axis] !== void 0) result = true;
|
|
4003
|
+
else {
|
|
4004
|
+
const own = ownAxes(part, parts, spec, memo);
|
|
4005
|
+
const hasKids = parts.some((c) => c.parent === part.id && !c.pin && !c.cover && !c.overlay);
|
|
4006
|
+
result = !own[axis] || (hasKids ? boxSized(spec, part.id, own)[axis] !== void 0 : typeof spec.values[part.id]?.[axis] === "number");
|
|
3421
4007
|
}
|
|
3422
|
-
|
|
4008
|
+
memo.set(key2, result);
|
|
4009
|
+
return result;
|
|
3423
4010
|
}
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
const
|
|
3427
|
-
if (!
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
else part.stretch = { ...part.stretch ?? {}, [side]: true };
|
|
3459
|
-
} else {
|
|
3460
|
-
const px = how === "fixed" ? typeof values[side] === "number" ? values[side] : box?.[side] : how;
|
|
3461
|
-
if (px === void 0) continue;
|
|
3462
|
-
values[side] = px;
|
|
3463
|
-
spec.sized = { ...spec.sized ?? {}, [id]: { ...spec.sized?.[id] ?? {}, [side]: px } };
|
|
3464
|
-
if (part.stretch) delete part.stretch[side];
|
|
3465
|
-
if (flowsAlong) delete part.grow;
|
|
3466
|
-
if (!part.parent && side === "width") delete part.fill;
|
|
3467
|
-
}
|
|
4011
|
+
function pinFromBoxes(spec, part) {
|
|
4012
|
+
const box = spec.boxes?.[part.id];
|
|
4013
|
+
const parent = part.parent ? spec.boxes?.[part.parent] : void 0;
|
|
4014
|
+
if (!box || !parent) return void 0;
|
|
4015
|
+
return { top: Math.round((box.y - parent.y) * 100) / 100, left: Math.round((box.x - parent.x) * 100) / 100 };
|
|
4016
|
+
}
|
|
4017
|
+
function alignedLayout(part, parts) {
|
|
4018
|
+
const layout = part.layout;
|
|
4019
|
+
if (!layout?.align) return layout;
|
|
4020
|
+
const { align, ...own } = layout;
|
|
4021
|
+
const flow = parts.filter((c) => c.parent === part.id && !c.pin && !c.cover && !c.overlay);
|
|
4022
|
+
const a2 = flow.length === 1 ? align[flow[0].id] : void 0;
|
|
4023
|
+
return a2 ? { ...own, primary: a2.primary ?? own.primary, counter: a2.counter ?? own.counter } : own;
|
|
4024
|
+
}
|
|
4025
|
+
function spacerWrappers(parts, variants, spacersOf, wrapsOf = /* @__PURE__ */ new Map()) {
|
|
4026
|
+
const wrapped = parts.filter((p2) => p2.parent && !p2.pin && !p2.cover && variants.some((v) => spacersOf.get(v)?.[p2.id] || wrapsOf.get(v)?.[p2.id]));
|
|
4027
|
+
for (const p2 of wrapped) {
|
|
4028
|
+
const parent = parts.find((x) => x.id === p2.parent);
|
|
4029
|
+
const row = parent?.layout?.direction === "HORIZONTAL";
|
|
4030
|
+
const id = `${p2.id}-wrapper`;
|
|
4031
|
+
const wrapper = { id, name: `${p2.name} wrapper`, kind: "frame", parent: p2.parent, layout: { direction: row ? "HORIZONTAL" : "VERTICAL", primary: "MIN", counter: "STRETCH" }, ...p2.grow ? { grow: p2.grow } : {} };
|
|
4032
|
+
parts.splice(parts.indexOf(p2), 0, wrapper);
|
|
4033
|
+
p2.parent = id;
|
|
4034
|
+
for (const v of variants) {
|
|
4035
|
+
const pad = wrapsOf.get(v)?.[p2.id];
|
|
4036
|
+
const space = spacersOf.get(v)?.[p2.id] ?? 0;
|
|
4037
|
+
const values = {};
|
|
4038
|
+
if (pad?.top) values.paddingTop = pad.top;
|
|
4039
|
+
if (pad?.right) values.paddingRight = pad.right;
|
|
4040
|
+
if (pad?.bottom) values.paddingBottom = pad.bottom;
|
|
4041
|
+
if (pad?.left) values.paddingLeft = pad.left;
|
|
4042
|
+
if (space) values[row ? "paddingLeft" : "paddingTop"] = (values[row ? "paddingLeft" : "paddingTop"] ?? 0) + space;
|
|
4043
|
+
v.values[id] = values;
|
|
4044
|
+
if (v.hidden?.includes(p2.id)) v.hidden.push(id);
|
|
3468
4045
|
}
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
4046
|
+
}
|
|
4047
|
+
}
|
|
4048
|
+
function textProperties(parts, story, argTypes, axes) {
|
|
4049
|
+
const properties = [];
|
|
4050
|
+
const props = propsOf$1(story);
|
|
4051
|
+
for (const [k, a2] of Object.entries(argTypes)) {
|
|
4052
|
+
const value = props[k];
|
|
4053
|
+
if (a2.kind !== "text" || NOT_AN_AXIS.test(k) || typeof value !== "string" || !value.trim()) continue;
|
|
4054
|
+
const part = parts.find((p2) => p2.kind === "text" && !p2.text && p2.characters?.trim() === value.trim());
|
|
4055
|
+
const name = axisName(k);
|
|
4056
|
+
if (!part || axes.has(name) || properties.some((x) => x.name === name)) continue;
|
|
4057
|
+
part.text = name;
|
|
4058
|
+
properties.push({ name, type: "TEXT", default: value, prop: k });
|
|
4059
|
+
}
|
|
4060
|
+
return properties;
|
|
4061
|
+
}
|
|
4062
|
+
function withoutIdleStates(variants) {
|
|
4063
|
+
const look2 = (v) => JSON.stringify([v.values, v.hidden ?? [], v.vectors ?? {}, v.pins ?? {}]);
|
|
4064
|
+
const rest = (v) => JSON.stringify(Object.entries(v.props).filter(([k]) => k !== "State"));
|
|
4065
|
+
const resting = new Map(variants.filter((v) => v.props.State === "Default").map((v) => [rest(v), look2(v)]));
|
|
4066
|
+
return variants.filter((v) => !["Hover", "Pressed", "Focus"].includes(v.props.State ?? "") || resting.get(rest(v)) !== look2(v));
|
|
4067
|
+
}
|
|
4068
|
+
function drawnAxes(axes, variants) {
|
|
4069
|
+
const look2 = (v) => JSON.stringify([v.values, v.hidden ?? [], v.vectors ?? {}, v.pins ?? {}]);
|
|
4070
|
+
let current = { axes, variants };
|
|
4071
|
+
for (const axis of axes) {
|
|
4072
|
+
const others = (v) => JSON.stringify(current.axes.filter((a2) => a2 !== axis).map((a2) => v.props[a2.name]));
|
|
4073
|
+
const twin = /* @__PURE__ */ new Map();
|
|
4074
|
+
for (const v of current.variants) if (v.props[axis.name] === axis.default) twin.set(others(v), v);
|
|
4075
|
+
const hoverTwin = /* @__PURE__ */ new Map();
|
|
4076
|
+
if (axis.name === "State") {
|
|
4077
|
+
for (const v of current.variants) if (v.props.State === "Hover") hoverTwin.set(others(v), v);
|
|
3474
4078
|
}
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
4079
|
+
const stand = (v) => current.variants.filter((x) => x.props[axis.name] !== v.props[axis.name] && others(x) === others(v));
|
|
4080
|
+
const differs = (v, from) => from.has(others(v)) ? look2(from.get(others(v))) !== look2(v) : from !== twin || stand(v).every((x) => look2(x) !== look2(v));
|
|
4081
|
+
const drawn = axis.values.filter(
|
|
4082
|
+
(value) => value === axis.default || current.variants.some((v) => v.props[axis.name] === value && differs(v, twin) && (!["Pressed", "Focus"].includes(value) || !hoverTwin.size || differs(v, hoverTwin)))
|
|
4083
|
+
);
|
|
4084
|
+
const values = axis.values.filter((value) => drawn.includes(value));
|
|
4085
|
+
const variants2 = current.variants.filter((v) => values.includes(v.props[axis.name]));
|
|
4086
|
+
const covered = new Set(variants2.filter((v) => v.props[axis.name] === axis.default).map(others));
|
|
4087
|
+
for (const v of current.variants) {
|
|
4088
|
+
if (values.includes(v.props[axis.name]) || covered.has(others(v))) continue;
|
|
4089
|
+
covered.add(others(v));
|
|
4090
|
+
variants2.push({ ...v, props: { ...v.props, [axis.name]: axis.default } });
|
|
3480
4091
|
}
|
|
4092
|
+
if (values.length > 1) current = { axes: current.axes.map((a2) => a2 === axis ? { ...a2, values } : a2), variants: variants2 };
|
|
4093
|
+
else
|
|
4094
|
+
current = {
|
|
4095
|
+
axes: current.axes.filter((a2) => a2 !== axis),
|
|
4096
|
+
variants: variants2.map((v) => ({ ...v, props: Object.fromEntries(Object.entries(v.props).filter(([k]) => k !== axis.name)) }))
|
|
4097
|
+
};
|
|
3481
4098
|
}
|
|
3482
|
-
return
|
|
4099
|
+
return current;
|
|
3483
4100
|
}
|
|
3484
|
-
function
|
|
3485
|
-
const
|
|
3486
|
-
const
|
|
3487
|
-
const
|
|
3488
|
-
const
|
|
3489
|
-
const
|
|
3490
|
-
|
|
3491
|
-
const
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
};
|
|
3497
|
-
for (const
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
record("not-found", 0, `no measured story of ${fix.component}`);
|
|
4101
|
+
function specsFromMeasure(file, opts = {}) {
|
|
4102
|
+
const known = opts.known ?? (() => true);
|
|
4103
|
+
const key2 = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
4104
|
+
const only = opts.only === void 0 ? void 0 : key2(opts.only);
|
|
4105
|
+
const groups = /* @__PURE__ */ new Map();
|
|
4106
|
+
for (const s of file.stories) {
|
|
4107
|
+
if (s.error || !s.spec) continue;
|
|
4108
|
+
const name = setNameOf$2(s.title);
|
|
4109
|
+
if (only !== void 0 && key2(name) !== only) continue;
|
|
4110
|
+
groups.set(name, [...groups.get(name) ?? [], s]);
|
|
4111
|
+
}
|
|
4112
|
+
const argTypesOf = (name) => Object.assign({}, ...(file.components ?? []).filter((c) => setNameOf$2(c.title) === name).map((c) => c.argTypes));
|
|
4113
|
+
const hints = {};
|
|
4114
|
+
for (const c of file.components ?? []) if (c.figma) hints[setNameOf$2(c.title)] = { ...hints[setNameOf$2(c.title)], ...c.figma };
|
|
4115
|
+
const components = [];
|
|
4116
|
+
const shots = {};
|
|
4117
|
+
const report = { sets: 0, variants: 0, stories: 0, skipped: [] };
|
|
4118
|
+
for (const [name, stories] of [...groups].sort(([a2], [b]) => a2.localeCompare(b))) {
|
|
4119
|
+
const built = setOf(name, stories, argTypesOf(name), file.storybook, known, hints[name]);
|
|
4120
|
+
if (!built) {
|
|
4121
|
+
report.skipped.push(name);
|
|
3506
4122
|
continue;
|
|
3507
4123
|
}
|
|
3508
|
-
const
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
4124
|
+
const spec = built.spec;
|
|
4125
|
+
components.push(spec);
|
|
4126
|
+
if (Object.keys(built.shots).length) shots[name] = built.shots;
|
|
4127
|
+
report.sets++;
|
|
4128
|
+
report.variants += spec.variants.length;
|
|
4129
|
+
report.stories += stories.length;
|
|
4130
|
+
}
|
|
4131
|
+
return { specs: { version: 1, generated: `Measured from ${file.storybook} on ${file.measuredAt} (bridge specs --measure).`, components }, report, shots, hints };
|
|
4132
|
+
}
|
|
4133
|
+
const FIGMA_FIXES_VERSION = 1;
|
|
4134
|
+
const DEFAULT_FIGMA_FIXES_FILE = "figma-fixes.json";
|
|
4135
|
+
class FigmaFixesError extends Error {
|
|
4136
|
+
constructor(problems) {
|
|
4137
|
+
super(`figma-fixes.json: ${problems.join("; ")}`);
|
|
4138
|
+
this.problems = problems;
|
|
4139
|
+
}
|
|
4140
|
+
problems;
|
|
4141
|
+
}
|
|
4142
|
+
const isObj$3 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
4143
|
+
const STATES = ["rest", "hover", "active", "focus-visible", "disabled"];
|
|
4144
|
+
const KINDS = ["part", "axis", "story", "status"];
|
|
4145
|
+
const BASE_KEYS = ["id", "component", "reason", "by", "where", "kind"];
|
|
4146
|
+
const KEYS = {
|
|
4147
|
+
part: ["part", "set", "width", "height", "direction", "align", "overlay", "hide"],
|
|
4148
|
+
axis: ["action", "arg", "property", "values"],
|
|
4149
|
+
story: ["use"],
|
|
4150
|
+
status: ["status"]
|
|
4151
|
+
};
|
|
4152
|
+
const PRIMARY = ["MIN", "CENTER", "MAX", "SPACE_BETWEEN"];
|
|
4153
|
+
const COUNTER = ["MIN", "CENTER", "MAX", "STRETCH"];
|
|
4154
|
+
const plain = (v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean";
|
|
4155
|
+
function whereProblems(w, at2) {
|
|
4156
|
+
if (!isObj$3(w)) return at2("where must be an object with args and/or state");
|
|
4157
|
+
for (const k of Object.keys(w)) if (k !== "args" && k !== "state") at2(`where.${k} is not known (args, state)`);
|
|
4158
|
+
if (w.args !== void 0 && (!isObj$3(w.args) || !Object.values(w.args).every(plain))) at2("where.args maps arg names to a text, number or true/false");
|
|
4159
|
+
if (w.state !== void 0 && !STATES.includes(w.state)) at2(`where.state is one of ${STATES.join(", ")}`);
|
|
4160
|
+
}
|
|
4161
|
+
function validateFigmaFixes(data) {
|
|
4162
|
+
const out = [];
|
|
4163
|
+
if (!isObj$3(data)) return ["expected an object with version and fixes"];
|
|
4164
|
+
if (data.version !== FIGMA_FIXES_VERSION) out.push(`version ${String(data.version)} is not supported (expected ${FIGMA_FIXES_VERSION})`);
|
|
4165
|
+
for (const k of Object.keys(data)) if (!["$schema", "version", "fixes"].includes(k)) out.push(`${k} is not known (version, fixes)`);
|
|
4166
|
+
if (!Array.isArray(data.fixes)) return [...out, "fixes must be a list"];
|
|
4167
|
+
const ids = /* @__PURE__ */ new Set();
|
|
4168
|
+
data.fixes.forEach((f, i) => {
|
|
4169
|
+
const label = isObj$3(f) && typeof f.id === "string" ? `fix ${f.id}` : `fix ${i + 1}`;
|
|
4170
|
+
const at2 = (why) => out.push(`${label}: ${why}`);
|
|
4171
|
+
if (!isObj$3(f)) return at2("must be an object");
|
|
4172
|
+
if (typeof f.id !== "string" || !/^[a-z0-9][a-z0-9-]{0,79}$/.test(f.id)) at2("id must be lower case letters, digits and dashes");
|
|
4173
|
+
else if (ids.has(f.id)) at2("id is repeated");
|
|
4174
|
+
else ids.add(f.id);
|
|
4175
|
+
if (typeof f.component !== "string" || !f.component.trim()) at2('component is missing (the Figma set name, like "Toggle")');
|
|
4176
|
+
if (typeof f.reason !== "string" || f.reason.trim().length < 8) at2("reason is missing: say why, in a sentence");
|
|
4177
|
+
else if (/\u2014/.test(f.reason)) at2("reason uses an em dash: use a colon or a comma");
|
|
4178
|
+
if (f.by !== void 0 && typeof f.by !== "string") at2("by must be a text");
|
|
4179
|
+
if (f.where !== void 0) whereProblems(f.where, at2);
|
|
4180
|
+
if (!KINDS.includes(f.kind)) return at2(`kind must be one of ${KINDS.join(", ")}`);
|
|
4181
|
+
const kind = f.kind;
|
|
4182
|
+
for (const k of Object.keys(f)) if (!BASE_KEYS.includes(k) && !KEYS[kind].includes(k)) at2(`${k} is not a key of a ${kind} fix`);
|
|
4183
|
+
if (kind === "part") partProblems(f, at2);
|
|
4184
|
+
if (kind === "axis") axisProblems(f, at2);
|
|
4185
|
+
if (kind === "story") {
|
|
4186
|
+
const u = f.use;
|
|
4187
|
+
if (!isObj$3(u) || typeof u.story !== "string" || !u.story) at2("use.story is the story id to draw the variant from");
|
|
4188
|
+
else {
|
|
4189
|
+
for (const k of Object.keys(u)) if (!["story", "args", "state"].includes(k)) at2(`use.${k} is not known (story, args, state)`);
|
|
4190
|
+
if (u.args !== void 0 && (!isObj$3(u.args) || !Object.values(u.args).every(plain))) at2("use.args maps arg names to a text, number or true/false");
|
|
4191
|
+
if (u.state !== void 0 && !STATES.includes(u.state)) at2(`use.state is one of ${STATES.join(", ")}`);
|
|
4192
|
+
}
|
|
4193
|
+
if (!isObj$3(f.where) || !f.where.args && !f.where.state) at2("where names the variant (args and/or state) the story is for");
|
|
4194
|
+
}
|
|
4195
|
+
if (kind === "status") {
|
|
4196
|
+
if (f.status === "matches") at2('status cannot be "matches": only the shot comparison says a component matches');
|
|
4197
|
+
else if (f.status !== void 0 && f.status !== "differs" && f.status !== "cant-check") at2("status is differs or cant-check (absent: a note)");
|
|
4198
|
+
}
|
|
4199
|
+
});
|
|
4200
|
+
return out;
|
|
4201
|
+
}
|
|
4202
|
+
function partProblems(f, at2) {
|
|
4203
|
+
if (typeof f.part !== "string" || !f.part.trim()) at2("part is a part id or a .class");
|
|
4204
|
+
const changes = ["set", "width", "height", "direction", "align", "overlay", "hide"].filter((k) => f[k] !== void 0);
|
|
4205
|
+
if (!changes.length) at2("changes nothing: give set, width, height, direction, align, overlay or hide");
|
|
4206
|
+
if (f.hide !== void 0 && typeof f.hide !== "boolean") at2("hide is true or false");
|
|
4207
|
+
if (f.hide === true && changes.length > 1) at2("hide goes alone: a hidden part has nothing else to change");
|
|
4208
|
+
if (f.set !== void 0) {
|
|
4209
|
+
if (!isObj$3(f.set) || !Object.keys(f.set).length) at2("set maps fields to values");
|
|
4210
|
+
else
|
|
4211
|
+
for (const [field, value] of Object.entries(f.set)) {
|
|
4212
|
+
if (!SPEC_FIELDS.includes(field)) {
|
|
4213
|
+
at2(`set.${field} is not a field (${SPEC_FIELDS.join(", ")})`);
|
|
3538
4214
|
continue;
|
|
3539
4215
|
}
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
}
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
const drop = new Set(scoped().filter((s) => baseline !== void 0 && propsOf$1(s)[arg] !== void 0 && !sameArg(propsOf$1(s)[arg], baseline)));
|
|
3551
|
-
file.stories = file.stories.filter((s) => !drop.has(s));
|
|
3552
|
-
if (entry) {
|
|
3553
|
-
delete entry.argTypes[arg];
|
|
3554
|
-
entry.figma ??= {};
|
|
3555
|
-
entry.figma.ignored = [.../* @__PURE__ */ new Set([...entry.figma.ignored ?? [], arg])];
|
|
3556
|
-
}
|
|
3557
|
-
record("applied", drop.size, `${arg} is not a Figma property${drop.size ? `: ${drop.size} stor${drop.size === 1 ? "y" : "ies"} at another value left out` : ""}`);
|
|
3558
|
-
}
|
|
3559
|
-
}
|
|
3560
|
-
} else if (fix.kind === "story") {
|
|
3561
|
-
const src = file.stories.find(
|
|
3562
|
-
(s) => s.id === fix.use.story && s.spec && !s.error && (!fix.use.args || Object.entries(fix.use.args).every(([k, v]) => sameArg(propsOf$1(s)[k], v))) && (!fix.use.state || storyState(s) === fix.use.state)
|
|
3563
|
-
);
|
|
3564
|
-
if (!src) {
|
|
3565
|
-
record("not-found", 0, `no measured render of story ${fix.use.story}${fix.use.args ? ` with ${JSON.stringify(fix.use.args)}` : ""}`);
|
|
3566
|
-
continue;
|
|
3567
|
-
}
|
|
3568
|
-
const target = fix.where ?? {};
|
|
3569
|
-
const others = new Set(scoped().filter((s) => s !== src));
|
|
3570
|
-
const copy = clone(src);
|
|
3571
|
-
const overrides = { ...copy.overrides ?? {}, ...target.args ?? {} };
|
|
3572
|
-
if (target.state === "disabled") overrides.disabled = true;
|
|
3573
|
-
copy.overrides = overrides;
|
|
3574
|
-
if (target.state && target.state !== "rest" && target.state !== "disabled") copy.state = target.state;
|
|
3575
|
-
else if (target.state) delete copy.state;
|
|
3576
|
-
if (lc$1(setNameOf$2(copy.title)) !== lc$1(fix.component)) copy.title = copy.title.split("/").slice(0, -1).concat(fix.component).join("/");
|
|
3577
|
-
mark(copy, fix.id);
|
|
3578
|
-
let placed = false;
|
|
3579
|
-
file.stories = file.stories.flatMap((s) => others.has(s) ? placed ? [] : (placed = true, [copy]) : [s]);
|
|
3580
|
-
if (!placed) file.stories.push(copy);
|
|
3581
|
-
record("applied", others.size + 1, `variant ${whereWords(target)} drawn from ${src.id}${others.size ? `, in place of ${others.size} other stor${others.size === 1 ? "y" : "ies"}` : ""}`);
|
|
3582
|
-
} else {
|
|
3583
|
-
const h2 = hints(fix.component);
|
|
3584
|
-
if (!h2) {
|
|
3585
|
-
record("not-found", 0, `no component entry for ${fix.component} in the measure`);
|
|
3586
|
-
continue;
|
|
4216
|
+
const color = COLOR_FIELDS.has(field);
|
|
4217
|
+
if (value === "full") {
|
|
4218
|
+
if (field !== "cornerRadius") at2(`set.${field}: "full" is for cornerRadius only`);
|
|
4219
|
+
} else if (value === null) {
|
|
4220
|
+
if (!color) at2(`set.${field} cannot be none (only colors can)`);
|
|
4221
|
+
} else if (typeof value === "number") {
|
|
4222
|
+
if (color) at2(`set.${field} is a color: a token path or null, not a number`);
|
|
4223
|
+
else if (!Number.isFinite(value)) at2(`set.${field} must be a finite number`);
|
|
4224
|
+
} else if (typeof value !== "string" || !value.trim()) at2(`set.${field} must be a token path, a number or null`);
|
|
4225
|
+
else if (field === "textDecoration" && !/^(UNDERLINE|STRIKETHROUGH|NONE)$/.test(value)) at2(`set.textDecoration is UNDERLINE, STRIKETHROUGH or NONE`);
|
|
3587
4226
|
}
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
4227
|
+
}
|
|
4228
|
+
for (const side of ["width", "height"]) {
|
|
4229
|
+
const v = f[side];
|
|
4230
|
+
if (v !== void 0 && !["hug", "fill", "fixed"].includes(v) && !(typeof v === "number" && v > 0)) at2(`${side} is hug, fill, fixed or a size in px`);
|
|
4231
|
+
}
|
|
4232
|
+
if (f.direction !== void 0 && f.direction !== "HORIZONTAL" && f.direction !== "VERTICAL") at2("direction is HORIZONTAL or VERTICAL");
|
|
4233
|
+
if (f.align !== void 0) {
|
|
4234
|
+
const a2 = f.align;
|
|
4235
|
+
if (!isObj$3(a2) || a2.primary === void 0 && a2.counter === void 0) at2("align gives primary and/or counter");
|
|
4236
|
+
else {
|
|
4237
|
+
if (a2.primary !== void 0 && !PRIMARY.includes(a2.primary)) at2(`align.primary is ${PRIMARY.join(", ")}`);
|
|
4238
|
+
if (a2.counter !== void 0 && !COUNTER.includes(a2.counter)) at2(`align.counter is ${COUNTER.join(", ")}`);
|
|
3600
4239
|
}
|
|
3601
|
-
const h = hints(fix.component);
|
|
3602
|
-
if (h && applied.at(-1).result === "applied") h.fixes = [.../* @__PURE__ */ new Set([...h.fixes ?? [], fix.id])];
|
|
3603
4240
|
}
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
}
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
if (w.state) args.push(`state=${w.state}`);
|
|
3610
|
-
return args.join(", ") || "every variant";
|
|
4241
|
+
if (f.overlay !== void 0 && typeof f.overlay !== "boolean") {
|
|
4242
|
+
const o = f.overlay;
|
|
4243
|
+
if (!isObj$3(o) || !Object.keys(o).length || !Object.entries(o).every(([k, v]) => ["top", "right", "bottom", "left"].includes(k) && typeof v === "number")) at2('overlay is true, false, or offsets in px ({ "top": 3, "left": 3 })');
|
|
4244
|
+
}
|
|
4245
|
+
if (f.part === "root" && (f.hide === true || f.overlay !== void 0)) at2("the root cannot be hidden or overlaid");
|
|
3611
4246
|
}
|
|
3612
|
-
function
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
4247
|
+
function axisProblems(f, at2) {
|
|
4248
|
+
const action = f.action;
|
|
4249
|
+
if (action !== "map" && action !== "ignore" && action !== "prune") return at2("action is map, ignore or prune");
|
|
4250
|
+
if (action !== "prune" && (typeof f.arg !== "string" || !f.arg)) at2(`${action} needs arg (the story arg, like "kind")`);
|
|
4251
|
+
if (action === "map") {
|
|
4252
|
+
if (f.property === void 0 && f.values === void 0) at2("map gives property (the Figma name) and/or values");
|
|
4253
|
+
if (f.property !== void 0 && (typeof f.property !== "string" || !f.property.trim())) at2("property is the Figma property name");
|
|
4254
|
+
if (f.values !== void 0 && (!isObj$3(f.values) || !Object.values(f.values).every((v) => typeof v === "string" && v.trim()))) at2("values maps code values to Figma values (texts)");
|
|
4255
|
+
else if (isObj$3(f.values)) {
|
|
4256
|
+
const figma = Object.values(f.values);
|
|
4257
|
+
if (new Set(figma).size !== figma.length) at2("values gives two code values the same Figma value: use prune for the one to drop");
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
4260
|
+
if (action === "ignore" && (f.property !== void 0 || f.values !== void 0)) at2("ignore takes no property or values");
|
|
4261
|
+
if (action === "prune") {
|
|
4262
|
+
if (!isObj$3(f.where) || !f.where.args && !f.where.state) at2("prune needs where (the args and/or state of the variants to drop)");
|
|
4263
|
+
if (f.property !== void 0 || f.values !== void 0) at2("prune takes no property or values");
|
|
4264
|
+
}
|
|
3623
4265
|
}
|
|
3624
|
-
function
|
|
3625
|
-
|
|
4266
|
+
function parseFigmaFixes(input) {
|
|
4267
|
+
let data = input;
|
|
4268
|
+
if (typeof input === "string") {
|
|
4269
|
+
try {
|
|
4270
|
+
data = JSON.parse(input);
|
|
4271
|
+
} catch (e) {
|
|
4272
|
+
throw new FigmaFixesError([`not JSON: ${e.message}`]);
|
|
4273
|
+
}
|
|
4274
|
+
}
|
|
4275
|
+
const problems = validateFigmaFixes(data);
|
|
4276
|
+
if (problems.length) throw new FigmaFixesError(problems);
|
|
4277
|
+
return data;
|
|
3626
4278
|
}
|
|
3627
|
-
const
|
|
3628
|
-
const STATE_PROPS = /* @__PURE__ */ new Set(["disabled", "checked", "indeterminate"]);
|
|
3629
|
-
const STATES = [
|
|
3630
|
-
{ value: "Default", of: (s) => !s.state && s.props?.disabled !== true },
|
|
3631
|
-
{ value: "Hover", of: (s) => s.state === "hover" && s.props?.disabled !== true },
|
|
3632
|
-
{ value: "Pressed", of: (s) => s.state === "active" && s.props?.disabled !== true },
|
|
3633
|
-
{ value: "Focus", of: (s) => s.state === "focus-visible" && s.props?.disabled !== true },
|
|
3634
|
-
{ value: "Disabled", of: (s) => s.props?.disabled === true }
|
|
3635
|
-
];
|
|
4279
|
+
const lc$1 = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
3636
4280
|
const setNameOf$1 = (title) => title.split("/").at(-1).trim();
|
|
3637
|
-
const axisName = (prop) => prop.charAt(0).toUpperCase() + prop.slice(1).replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase();
|
|
3638
4281
|
const propsOf = (s) => ({ ...s.props ?? {}, ...s.overrides ?? {} });
|
|
3639
|
-
|
|
4282
|
+
const sameArg = (a2, b) => a2 === b || a2 !== void 0 && b !== void 0 && String(a2).toLowerCase() === String(b).toLowerCase();
|
|
4283
|
+
function storyMatchesWhere(s, where) {
|
|
4284
|
+
if (!where) return true;
|
|
3640
4285
|
const p2 = propsOf(s);
|
|
3641
|
-
|
|
4286
|
+
if (where.args && !Object.entries(where.args).every(([k, v]) => sameArg(p2[k], v))) return false;
|
|
4287
|
+
if (where.state && storyState(s) !== where.state) return false;
|
|
4288
|
+
return true;
|
|
3642
4289
|
}
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
const raw = spec.raw[partId] ?? {};
|
|
3648
|
-
for (const field of Object.keys(v)) {
|
|
3649
|
-
const value = v[field];
|
|
3650
|
-
if (typeof value !== "string" || value.startsWith("calc(") || known(value)) continue;
|
|
3651
|
-
const literal = raw[field];
|
|
3652
|
-
if (literal === void 0) delete v[field];
|
|
3653
|
-
else v[field] = literal;
|
|
3654
|
-
}
|
|
3655
|
-
for (const field of LITERAL_FIELDS) if (v[field] === void 0 && typeof raw[field] === "string") v[field] = raw[field];
|
|
3656
|
-
if (hasChildren) {
|
|
3657
|
-
if (typeof v.width === "number" && !fills) delete v.width;
|
|
3658
|
-
if (typeof v.height === "number") delete v.height;
|
|
4290
|
+
function partsNamed(spec, sel) {
|
|
4291
|
+
if (sel.startsWith(".")) {
|
|
4292
|
+
const cls = sel.slice(1);
|
|
4293
|
+
return spec.parts.filter((p2) => (p2.source ?? "").split(/[\s,]+/).map((x) => x.replace(/^\./, "")).includes(cls));
|
|
3659
4294
|
}
|
|
3660
|
-
|
|
3661
|
-
if (sized?.height !== void 0) v.height = sized.height;
|
|
3662
|
-
return v;
|
|
4295
|
+
return spec.parts.filter((p2) => p2.id === sel);
|
|
3663
4296
|
}
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
const kids = spec.parts.filter((
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
const
|
|
3671
|
-
const
|
|
3672
|
-
const
|
|
3673
|
-
const
|
|
3674
|
-
const
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
if (
|
|
3678
|
-
return
|
|
4297
|
+
const clone = (v) => JSON.parse(JSON.stringify(v));
|
|
4298
|
+
function wordsIn(spec, id) {
|
|
4299
|
+
const kids = spec.parts.filter((p2) => p2.parent === id);
|
|
4300
|
+
return kids.some((k) => k.kind === "text" && !!k.characters?.trim() || wordsIn(spec, k.id));
|
|
4301
|
+
}
|
|
4302
|
+
function ownSize(spec, part, side) {
|
|
4303
|
+
const id = part.id;
|
|
4304
|
+
const box = spec.boxes[id];
|
|
4305
|
+
const value = spec.values[id]?.[side];
|
|
4306
|
+
const measured = typeof value === "number" ? value : box?.[side];
|
|
4307
|
+
const skip = (why) => ({ part: id, side, why, ...measured !== void 0 && why !== "unmeasured" ? { measured } : {} });
|
|
4308
|
+
if (!part.parent && side === "width" && part.fill) return skip("fills");
|
|
4309
|
+
const css = spec.sized?.[id]?.[side];
|
|
4310
|
+
if (typeof css === "number") return css;
|
|
4311
|
+
if (side === "width" && box && wordsIn(spec, id) && boxSized(spec, id, { width: true, height: true }).width === void 0) return skip("words");
|
|
4312
|
+
return measured ?? skip("unmeasured");
|
|
3679
4313
|
}
|
|
3680
|
-
function
|
|
3681
|
-
const
|
|
3682
|
-
const
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
const
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
([
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
if (!plain2.length) return void 0;
|
|
3697
|
-
const axes = [];
|
|
3698
|
-
for (const [prop, a2] of flags) {
|
|
3699
|
-
const def = String(baseline(prop, a2) === true);
|
|
3700
|
-
axes.push({ name: propName(prop), prop, values: [figmaValue(prop, def), figmaValue(prop, def === "true" ? "false" : "true")], default: figmaValue(prop, def) });
|
|
3701
|
-
}
|
|
3702
|
-
for (const [prop, a2] of Object.entries(argTypes)) {
|
|
3703
|
-
if (a2.kind !== "enum" || NOT_AN_AXIS.test(prop) || !a2.options || a2.options.length < 2 || a2.options.length > 12) continue;
|
|
3704
|
-
const seen = new Set(plain2.map((s) => String(propsOf(s)[prop] ?? a2.default ?? a2.options[0])));
|
|
3705
|
-
const values = a2.options.filter((o) => seen.has(o));
|
|
3706
|
-
if (values.length < 2) continue;
|
|
3707
|
-
const def = a2.default !== void 0 && values.includes(String(a2.default)) ? String(a2.default) : values[0];
|
|
3708
|
-
axes.push({ name: propName(prop), prop, values: [...new Set(values.map((v) => figmaValue(prop, v)))], default: figmaValue(prop, def) });
|
|
3709
|
-
}
|
|
3710
|
-
if ("checked" in argTypes || plain2.some((s) => "checked" in propsOf(s))) {
|
|
3711
|
-
const values = ["false", "true", "mixed"].filter((v) => plain2.some((s) => checkedOf(s) === v));
|
|
3712
|
-
if (values.length > 1) axes.push({ name: "Checked", values, default: values[0] });
|
|
3713
|
-
}
|
|
3714
|
-
const states = STATES.filter((st) => plain2.some(st.of)).map((st) => st.value);
|
|
3715
|
-
if (states.length > 1) axes.push({ name: "State", values: states, default: states[0] });
|
|
3716
|
-
const keyOf = (s) => {
|
|
3717
|
-
const props = {};
|
|
3718
|
-
for (const axis of axes) {
|
|
3719
|
-
const flag = flags.find(([k]) => k === axis.prop);
|
|
3720
|
-
const value = axis.name === "State" ? STATES.find((st) => st.of(s))?.value : axis.name === "Checked" ? checkedOf(s) : flag ? figmaValue(flag[0], String(valueOf(s, flag[0], flag[1]))) : propsOf(s)[axis.prop] === void 0 ? axis.default : figmaValue(axis.prop, String(propsOf(s)[axis.prop]));
|
|
3721
|
-
if (value === void 0 || !axis.values.includes(value)) return void 0;
|
|
3722
|
-
props[axis.name] = value;
|
|
3723
|
-
}
|
|
3724
|
-
return props;
|
|
3725
|
-
};
|
|
3726
|
-
const candidates = /* @__PURE__ */ new Map();
|
|
3727
|
-
for (const s of plain2) {
|
|
3728
|
-
const props = keyOf(s);
|
|
3729
|
-
if (!props) continue;
|
|
3730
|
-
const k = JSON.stringify(props);
|
|
3731
|
-
if (!candidates.has(k)) candidates.set(k, { props, stories: [] });
|
|
3732
|
-
candidates.get(k).stories.push(s);
|
|
3733
|
-
}
|
|
3734
|
-
const storyFor = /* @__PURE__ */ new Map();
|
|
3735
|
-
if (axes.some((a2) => a2.name === "State")) {
|
|
3736
|
-
const rest = (p2) => JSON.stringify(Object.entries(p2).filter(([k]) => k !== "State"));
|
|
3737
|
-
const groups = /* @__PURE__ */ new Map();
|
|
3738
|
-
for (const c of candidates.values()) groups.set(rest(c.props), [...groups.get(rest(c.props)) ?? [], c]);
|
|
3739
|
-
for (const [key2, group] of groups) {
|
|
3740
|
-
const ids = [...new Set(group.flatMap((c) => c.stories.map((s) => s.id)))];
|
|
3741
|
-
const score = (id) => group.filter((c) => c.stories.some((s) => s.id === id)).length;
|
|
3742
|
-
storyFor.set(key2, ids.reduce((best, id) => score(id) > score(best) ? id : best, ids[0]));
|
|
4314
|
+
function patchSpec(spec, fix) {
|
|
4315
|
+
const skipped = [];
|
|
4316
|
+
const targets = partsNamed(spec, fix.part);
|
|
4317
|
+
if (!targets.length) return { hit: false, skipped };
|
|
4318
|
+
let laid = false;
|
|
4319
|
+
for (const part of targets) {
|
|
4320
|
+
const id = part.id;
|
|
4321
|
+
const box = spec.boxes[id];
|
|
4322
|
+
const parent = part.parent ? spec.parts.find((p2) => p2.id === part.parent) : void 0;
|
|
4323
|
+
if (fix.hide) {
|
|
4324
|
+
const gone = /* @__PURE__ */ new Set([id]);
|
|
4325
|
+
for (const p2 of spec.parts) if (p2.parent && gone.has(p2.parent)) gone.add(p2.id);
|
|
4326
|
+
spec.parts = spec.parts.filter((p2) => !gone.has(p2.id));
|
|
4327
|
+
for (const map of [spec.values, spec.raw, spec.tokens, spec.boxes, spec.sized ?? {}, spec.spacers ?? {}, spec.vectors ?? {}]) for (const g of gone) delete map[g];
|
|
4328
|
+
laid = true;
|
|
4329
|
+
continue;
|
|
3743
4330
|
}
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
4331
|
+
const values = spec.values[id] ??= {};
|
|
4332
|
+
for (const [field, value] of Object.entries(fix.set ?? {})) {
|
|
4333
|
+
values[field] = value === "full" ? box ? Math.min(box.width, box.height) / 2 : 9999 : value;
|
|
4334
|
+
laid = true;
|
|
3747
4335
|
}
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
for (const p2 of parts) {
|
|
3756
|
-
if (!p2.overlay || p2.pin || p2.cover) continue;
|
|
3757
|
-
const pin = pinFromBoxes(baseSpec, p2);
|
|
3758
|
-
if (pin) p2.pin = pin;
|
|
3759
|
-
else p2.cover = true;
|
|
3760
|
-
}
|
|
3761
|
-
const paints = (id) => {
|
|
3762
|
-
const v = baseSpec.values[id] ?? {};
|
|
3763
|
-
return [v.fill, v.stroke].some((x) => x !== void 0 && x !== null);
|
|
3764
|
-
};
|
|
3765
|
-
for (const p2 of [...parts].reverse()) {
|
|
3766
|
-
if (!p2.parent || p2.kind !== "frame" || p2.pin || p2.cover || p2.overlay || paints(p2.id)) continue;
|
|
3767
|
-
const kids = parts.filter((c) => c.parent === p2.id);
|
|
3768
|
-
if (kids.length && kids.every((c) => c.overlay || c.pin || c.cover)) p2.cover = true;
|
|
3769
|
-
}
|
|
3770
|
-
const aligners = new Set(
|
|
3771
|
-
parts.filter((p2) => {
|
|
3772
|
-
const flow = parts.filter((c) => c.parent === p2.id && !c.pin && !c.cover && !c.overlay);
|
|
3773
|
-
return flow.length === 1 && !!p2.layout?.align?.[flow[0].id];
|
|
3774
|
-
}).map((p2) => p2.id)
|
|
3775
|
-
);
|
|
3776
|
-
for (const p2 of parts) if (p2.layout) p2.layout = alignedLayout(p2, parts);
|
|
3777
|
-
const parents = new Set(parts.filter((p2) => !p2.pin && !p2.cover).map((p2) => p2.parent).filter(Boolean));
|
|
3778
|
-
const variants = [];
|
|
3779
|
-
const axesMemo = /* @__PURE__ */ new Map();
|
|
3780
|
-
const shotOf = /* @__PURE__ */ new Map();
|
|
3781
|
-
const spacersOf = /* @__PURE__ */ new Map();
|
|
3782
|
-
const wrapsOf = /* @__PURE__ */ new Map();
|
|
3783
|
-
for (const { props, story: story2 } of byVariant.values()) {
|
|
3784
|
-
const m = story2.spec;
|
|
3785
|
-
const pairs = story2 === base.story ? new Map(parts.map((p2) => [p2.id, p2.id])) : pairParts(baseSpec.parts, m);
|
|
3786
|
-
const values = {};
|
|
3787
|
-
const vectors = {};
|
|
3788
|
-
const pins = {};
|
|
3789
|
-
const hidden = [];
|
|
3790
|
-
const spacers = {};
|
|
3791
|
-
const wraps = {};
|
|
3792
|
-
const layouts = {};
|
|
3793
|
-
for (const p2 of parts) {
|
|
3794
|
-
const mid = pairs.get(p2.id);
|
|
3795
|
-
if (mid === void 0) {
|
|
3796
|
-
hidden.push(p2.id);
|
|
4336
|
+
for (const side of ["width", "height"]) {
|
|
4337
|
+
const how = fix[side];
|
|
4338
|
+
if (how === void 0) continue;
|
|
4339
|
+
const flowsAlong = parent?.layout?.direction === (side === "width" ? "HORIZONTAL" : "VERTICAL");
|
|
4340
|
+
const px = how === "fixed" ? ownSize(spec, part, side) : how;
|
|
4341
|
+
if (typeof px === "object") {
|
|
4342
|
+
skipped.push(px);
|
|
3797
4343
|
continue;
|
|
3798
4344
|
}
|
|
3799
|
-
|
|
3800
|
-
if (
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
if (
|
|
4345
|
+
laid = true;
|
|
4346
|
+
if (px === "hug") {
|
|
4347
|
+
delete values[side];
|
|
4348
|
+
if (spec.sized?.[id]) delete spec.sized[id][side];
|
|
4349
|
+
if (part.stretch) delete part.stretch[side];
|
|
4350
|
+
if (flowsAlong) delete part.grow;
|
|
4351
|
+
if (!part.parent && side === "width") delete part.fill;
|
|
4352
|
+
} else if (px === "fill") {
|
|
4353
|
+
if (spec.sized?.[id]) delete spec.sized[id][side];
|
|
4354
|
+
if (!part.parent) {
|
|
4355
|
+
if (side === "width") part.fill = true;
|
|
4356
|
+
} else if (flowsAlong) part.grow = true;
|
|
4357
|
+
else part.stretch = { ...part.stretch ?? {}, [side]: true };
|
|
4358
|
+
} else {
|
|
4359
|
+
values[side] = px;
|
|
4360
|
+
spec.sized = { ...spec.sized ?? {}, [id]: { ...spec.sized?.[id] ?? {}, [side]: px } };
|
|
4361
|
+
if (part.stretch) delete part.stretch[side];
|
|
4362
|
+
if (flowsAlong) delete part.grow;
|
|
4363
|
+
if (!part.parent && side === "width") delete part.fill;
|
|
3808
4364
|
}
|
|
3809
|
-
if (mp?.wrap) wraps[p2.id] = mp.wrap.padding;
|
|
3810
|
-
const vec = p2.kind === "vector" ? m.vectors?.[mid] : void 0;
|
|
3811
|
-
if (vec) vectors[p2.id] = { svg: vec.svg, strokes: vec.strokes.every((v) => typeof v !== "string" || known(v)) ? [...vec.strokes] : [] };
|
|
3812
4365
|
}
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
const from = variants.find((x) => JSON.stringify(x.values) === JSON.stringify(v.values) && Object.entries(v.props).every(([k, val]) => x.props[k] === val));
|
|
3828
|
-
const shot = from && shotOf.get(from);
|
|
3829
|
-
if (shot) shots[variantKeyOf(v.props)] = shot;
|
|
3830
|
-
});
|
|
3831
|
-
return { spec: { ...spec, hash: hashSpec(spec) }, shots };
|
|
3832
|
-
}
|
|
3833
|
-
const TEXT_FIELDS = /* @__PURE__ */ new Set(["textFill", "fontFamily", "fontSize", "fontWeight", "lineHeight", "letterSpacing", "textDecoration"]);
|
|
3834
|
-
function textRootInFrame(parts, variants) {
|
|
3835
|
-
const root = parts.find((p2) => !p2.parent);
|
|
3836
|
-
if (!root || root.kind !== "text") return;
|
|
3837
|
-
const id = `${root.id}-text`;
|
|
3838
|
-
const text = { ...root, id, name: `${root.name} text`, parent: root.id };
|
|
3839
|
-
parts.splice(parts.indexOf(root), 1, { id: root.id, name: root.name, kind: "frame", ...root.source ? { source: root.source } : {}, layout: { direction: "HORIZONTAL", primary: "MIN", counter: "MIN" } }, text);
|
|
3840
|
-
for (const v of variants) {
|
|
3841
|
-
const all = v.values[root.id] ?? {};
|
|
3842
|
-
v.values[root.id] = Object.fromEntries(Object.entries(all).filter(([f, value]) => !TEXT_FIELDS.has(f) && !((f === "width" || f === "height") && typeof value === "number")));
|
|
3843
|
-
v.values[id] = Object.fromEntries(Object.entries(all).filter(([f]) => TEXT_FIELDS.has(f)));
|
|
3844
|
-
if (v.hidden?.includes(root.id)) v.hidden.push(id);
|
|
4366
|
+
if (fix.direction || fix.align) {
|
|
4367
|
+
laid = true;
|
|
4368
|
+
part.layout = { direction: "HORIZONTAL", primary: "MIN", counter: "MIN", ...part.layout ?? {} };
|
|
4369
|
+
if (fix.direction) part.layout.direction = fix.direction;
|
|
4370
|
+
if (fix.align?.primary) part.layout.primary = fix.align.primary;
|
|
4371
|
+
if (fix.align?.counter) part.layout.counter = fix.align.counter;
|
|
4372
|
+
}
|
|
4373
|
+
if (fix.overlay !== void 0) {
|
|
4374
|
+
laid = true;
|
|
4375
|
+
delete part.cover;
|
|
4376
|
+
delete part.pin;
|
|
4377
|
+
if (fix.overlay === true) part.cover = true;
|
|
4378
|
+
else if (fix.overlay !== false) part.pin = { ...fix.overlay };
|
|
4379
|
+
}
|
|
3845
4380
|
}
|
|
4381
|
+
return { hit: laid, skipped };
|
|
3846
4382
|
}
|
|
3847
|
-
function
|
|
3848
|
-
const
|
|
3849
|
-
const
|
|
3850
|
-
const
|
|
3851
|
-
const
|
|
3852
|
-
const
|
|
3853
|
-
const
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
return {
|
|
3857
|
-
width: !(!part.parent && part.fill) && !acrossW && !alongW && !part.stretch?.width,
|
|
3858
|
-
height: !acrossH && !alongH && !part.stretch?.height
|
|
4383
|
+
function applyFixes(measured, fixes) {
|
|
4384
|
+
const list = Array.isArray(fixes) ? fixes : fixes.fixes;
|
|
4385
|
+
const file = clone(measured);
|
|
4386
|
+
const before = new Set((file.figmaFixes?.applied ?? []).filter((a2) => a2.result === "applied").map((a2) => a2.id));
|
|
4387
|
+
const applied = [];
|
|
4388
|
+
const entryOf = (component) => (file.components ?? []).find((c) => lc$1(setNameOf$1(c.title)) === lc$1(component));
|
|
4389
|
+
const hints = (component) => {
|
|
4390
|
+
const c = entryOf(component);
|
|
4391
|
+
return c ? c.figma ??= {} : void 0;
|
|
3859
4392
|
};
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
const
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
4393
|
+
const mark = (s, id) => {
|
|
4394
|
+
s.fixes = [.../* @__PURE__ */ new Set([...s.fixes ?? [], id])];
|
|
4395
|
+
};
|
|
4396
|
+
for (const fix of list) {
|
|
4397
|
+
const record = (result, stories, detail) => applied.push({ id: fix.id, kind: fix.kind, component: fix.component, result, stories, detail });
|
|
4398
|
+
if (before.has(fix.id)) {
|
|
4399
|
+
record("already", 0, "already applied to this file");
|
|
4400
|
+
continue;
|
|
4401
|
+
}
|
|
4402
|
+
const mine = () => file.stories.filter((s) => lc$1(setNameOf$1(s.title)) === lc$1(fix.component));
|
|
4403
|
+
if (!mine().length) {
|
|
4404
|
+
record("not-found", 0, `no measured story of ${fix.component}`);
|
|
4405
|
+
continue;
|
|
4406
|
+
}
|
|
4407
|
+
const scoped = () => mine().filter((s) => storyMatchesWhere(s, fix.where));
|
|
4408
|
+
if (fix.kind === "part") {
|
|
4409
|
+
let n = 0;
|
|
4410
|
+
let matched = false;
|
|
4411
|
+
const unpinned = [];
|
|
4412
|
+
for (const s of scoped()) {
|
|
4413
|
+
let hit = false;
|
|
4414
|
+
for (const spec of [s.spec, ...s.instances ?? []]) {
|
|
4415
|
+
if (!spec) continue;
|
|
4416
|
+
const r = patchSpec(spec, fix);
|
|
4417
|
+
if (r.hit) hit = true;
|
|
4418
|
+
if (r.hit || r.skipped.length) matched = true;
|
|
4419
|
+
for (const skip of r.skipped) unpinned.push({ story: s, skip });
|
|
4420
|
+
}
|
|
4421
|
+
if (hit) {
|
|
4422
|
+
n++;
|
|
4423
|
+
mark(s, fix.id);
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
const skippedWords = unpinned.length ? skippedSizeWords(unpinned) : "";
|
|
4427
|
+
if (n) record("applied", n, `${describePartFix(fix)} on ${n} stor${n === 1 ? "y" : "ies"}${skippedWords ? `; ${skippedWords}` : ""}`);
|
|
4428
|
+
else if (matched) record("skipped", 0, `nothing laid on: ${skippedWords}`);
|
|
4429
|
+
else record("not-found", 0, `no part ${fix.part} in the ${scoped().length ? "stories it names" : "variants where names"}`);
|
|
4430
|
+
} else if (fix.kind === "axis") {
|
|
4431
|
+
const h2 = hints(fix.component);
|
|
4432
|
+
if (fix.action === "prune") {
|
|
4433
|
+
const drop = new Set(scoped());
|
|
4434
|
+
if (!drop.size) {
|
|
4435
|
+
record("not-found", 0, "no measured variant matches where");
|
|
4436
|
+
continue;
|
|
4437
|
+
}
|
|
4438
|
+
file.stories = file.stories.filter((s) => !drop.has(s));
|
|
4439
|
+
if (h2) h2.pruned = [...h2.pruned ?? [], fix.where];
|
|
4440
|
+
record("applied", drop.size, `dropped ${drop.size} variant stor${drop.size === 1 ? "y" : "ies"}`);
|
|
4441
|
+
} else {
|
|
4442
|
+
const arg = fix.arg;
|
|
4443
|
+
const entry = entryOf(fix.component);
|
|
4444
|
+
const known = !!entry?.argTypes[arg] || mine().some((s) => arg in propsOf(s));
|
|
4445
|
+
if (!known) {
|
|
4446
|
+
record("not-found", 0, `${fix.component} has no arg ${arg}`);
|
|
4447
|
+
continue;
|
|
4448
|
+
}
|
|
4449
|
+
if (fix.action === "map") {
|
|
4450
|
+
if (h2) {
|
|
4451
|
+
if (fix.property) h2.properties = { ...h2.properties ?? {}, [arg]: fix.property };
|
|
4452
|
+
if (fix.values) h2.values = { ...h2.values ?? {}, [arg]: { ...h2.values?.[arg] ?? {}, ...fix.values } };
|
|
4453
|
+
}
|
|
4454
|
+
record("applied", 0, `${arg} drawn as ${fix.property ?? arg}${fix.values ? ` (${Object.entries(fix.values).map(([c, f]) => `${c} as ${f}`).join(", ")})` : ""}`);
|
|
4455
|
+
} else {
|
|
4456
|
+
const at2 = entry?.argTypes[arg];
|
|
4457
|
+
const lead = mine().find((s) => !s.overrides || !(arg in s.overrides));
|
|
4458
|
+
const baseline = at2?.default ?? (lead ? propsOf(lead)[arg] : void 0) ?? (at2?.kind === "boolean" ? false : void 0);
|
|
4459
|
+
const drop = new Set(scoped().filter((s) => baseline !== void 0 && propsOf(s)[arg] !== void 0 && !sameArg(propsOf(s)[arg], baseline)));
|
|
4460
|
+
file.stories = file.stories.filter((s) => !drop.has(s));
|
|
4461
|
+
if (entry) {
|
|
4462
|
+
delete entry.argTypes[arg];
|
|
4463
|
+
entry.figma ??= {};
|
|
4464
|
+
entry.figma.ignored = [.../* @__PURE__ */ new Set([...entry.figma.ignored ?? [], arg])];
|
|
4465
|
+
}
|
|
4466
|
+
record("applied", drop.size, `${arg} is not a Figma property${drop.size ? `: ${drop.size} stor${drop.size === 1 ? "y" : "ies"} at another value left out` : ""}`);
|
|
4467
|
+
}
|
|
4468
|
+
}
|
|
4469
|
+
} else if (fix.kind === "story") {
|
|
4470
|
+
const src = file.stories.find(
|
|
4471
|
+
(s) => s.id === fix.use.story && s.spec && !s.error && (!fix.use.args || Object.entries(fix.use.args).every(([k, v]) => sameArg(propsOf(s)[k], v))) && (!fix.use.state || storyState(s) === fix.use.state)
|
|
4472
|
+
);
|
|
4473
|
+
if (!src) {
|
|
4474
|
+
record("not-found", 0, `no measured render of story ${fix.use.story}${fix.use.args ? ` with ${JSON.stringify(fix.use.args)}` : ""}`);
|
|
4475
|
+
continue;
|
|
4476
|
+
}
|
|
4477
|
+
const target = fix.where ?? {};
|
|
4478
|
+
const others = new Set(scoped().filter((s) => s !== src));
|
|
4479
|
+
const copy = clone(src);
|
|
4480
|
+
const overrides = { ...copy.overrides ?? {}, ...target.args ?? {} };
|
|
4481
|
+
if (target.state === "disabled") overrides.disabled = true;
|
|
4482
|
+
copy.overrides = overrides;
|
|
4483
|
+
if (target.state && target.state !== "rest" && target.state !== "disabled") copy.state = target.state;
|
|
4484
|
+
else if (target.state) delete copy.state;
|
|
4485
|
+
if (lc$1(setNameOf$1(copy.title)) !== lc$1(fix.component)) copy.title = copy.title.split("/").slice(0, -1).concat(fix.component).join("/");
|
|
4486
|
+
mark(copy, fix.id);
|
|
4487
|
+
let placed = false;
|
|
4488
|
+
file.stories = file.stories.flatMap((s) => others.has(s) ? placed ? [] : (placed = true, [copy]) : [s]);
|
|
4489
|
+
if (!placed) file.stories.push(copy);
|
|
4490
|
+
record("applied", others.size + 1, `variant ${whereWords(target)} drawn from ${src.id}${others.size ? `, in place of ${others.size} other stor${others.size === 1 ? "y" : "ies"}` : ""}`);
|
|
4491
|
+
} else {
|
|
4492
|
+
const h2 = hints(fix.component);
|
|
4493
|
+
if (!h2) {
|
|
4494
|
+
record("not-found", 0, `no component entry for ${fix.component} in the measure`);
|
|
4495
|
+
continue;
|
|
4496
|
+
}
|
|
4497
|
+
if (fix.status) {
|
|
4498
|
+
h2.status = [...h2.status ?? [], { status: fix.status, reason: fix.reason, fix: fix.id, ...fix.where ? { where: fix.where } : {} }];
|
|
4499
|
+
if (!fix.where) {
|
|
4500
|
+
const st = (file.statuses ?? []).find((x) => lc$1(x.name) === lc$1(fix.component));
|
|
4501
|
+
if (st && st.status !== fix.status) {
|
|
4502
|
+
st.status = fix.status;
|
|
4503
|
+
delete st.reason;
|
|
4504
|
+
st.summary = fix.reason;
|
|
4505
|
+
}
|
|
4506
|
+
}
|
|
4507
|
+
} else h2.notes = [...h2.notes ?? [], { text: fix.reason, fix: fix.id, ...fix.where ? { where: fix.where } : {} }];
|
|
4508
|
+
record("applied", 0, fix.status ? `${fix.status === "differs" ? "Differs" : "Can't check"}: ${fix.reason}` : `note: ${fix.reason}`);
|
|
3911
4509
|
}
|
|
4510
|
+
const h = hints(fix.component);
|
|
4511
|
+
if (h && applied.at(-1).result === "applied") h.fixes = [.../* @__PURE__ */ new Set([...h.fixes ?? [], fix.id])];
|
|
3912
4512
|
}
|
|
4513
|
+
file.figmaFixes = { applied: [...(file.figmaFixes?.applied ?? []).filter((a2) => a2.result === "applied"), ...applied.filter((a2) => a2.result !== "already")] };
|
|
4514
|
+
return { file, applied };
|
|
3913
4515
|
}
|
|
3914
|
-
|
|
3915
|
-
const
|
|
3916
|
-
const
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
4516
|
+
const variantWords = (s) => {
|
|
4517
|
+
const p2 = propsOf(s);
|
|
4518
|
+
const args = Object.keys(s.overrides ?? {}).filter((k) => k !== "disabled").map((k) => `${k}=${String(p2[k])}`);
|
|
4519
|
+
const state = storyState(s);
|
|
4520
|
+
return `${s.id}${args.length || state !== "rest" ? ` (${[...args, ...state !== "rest" ? [state] : []].join(", ")})` : ""}`;
|
|
4521
|
+
};
|
|
4522
|
+
function skippedSizeWords(list) {
|
|
4523
|
+
const why = {
|
|
4524
|
+
words: "it hugs its text in code, so the measured px is that story's words, not a width of its own",
|
|
4525
|
+
fills: "it fills its container in code, so the measured px is the container's",
|
|
4526
|
+
unmeasured: "the measure has no size for it in that story"
|
|
4527
|
+
};
|
|
4528
|
+
const groups = /* @__PURE__ */ new Map();
|
|
4529
|
+
for (const x of list) {
|
|
4530
|
+
const k = `${x.skip.part}|${x.skip.side}|${x.skip.why}`;
|
|
4531
|
+
groups.set(k, [...groups.get(k) ?? [], x]);
|
|
3925
4532
|
}
|
|
3926
|
-
return
|
|
4533
|
+
return [...groups.values()].map((g) => {
|
|
4534
|
+
const { part, side, why: w } = g[0].skip;
|
|
4535
|
+
const stories = [...new Set(g.map((x) => `${variantWords(x.story)}${x.skip.measured !== void 0 ? ` ${Math.round(x.skip.measured * 100) / 100} px` : ""}`))];
|
|
4536
|
+
return `${part} ${side} not fixed on ${stories.length} stor${stories.length === 1 ? "y" : "ies"} (${why[w]}):${stories.join(", ")}`;
|
|
4537
|
+
}).join("; ");
|
|
3927
4538
|
}
|
|
3928
|
-
function
|
|
3929
|
-
const
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
return variants.filter((v) => !["Hover", "Pressed", "Focus"].includes(v.props.State ?? "") || resting.get(rest(v)) !== look2(v));
|
|
4539
|
+
function whereWords(w) {
|
|
4540
|
+
const args = Object.entries(w.args ?? {}).map(([k, v]) => `${k}=${String(v)}`);
|
|
4541
|
+
if (w.state) args.push(`state=${w.state}`);
|
|
4542
|
+
return args.join(", ") || "every variant";
|
|
3933
4543
|
}
|
|
3934
|
-
function
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
const stand = (v) => current.variants.filter((x) => x.props[axis.name] !== v.props[axis.name] && others(x) === others(v));
|
|
3946
|
-
const differs = (v, from) => from.has(others(v)) ? look2(from.get(others(v))) !== look2(v) : from !== twin || stand(v).every((x) => look2(x) !== look2(v));
|
|
3947
|
-
const drawn = axis.values.filter(
|
|
3948
|
-
(value) => value === axis.default || current.variants.some((v) => v.props[axis.name] === value && differs(v, twin) && (!["Pressed", "Focus"].includes(value) || !hoverTwin.size || differs(v, hoverTwin)))
|
|
3949
|
-
);
|
|
3950
|
-
const values = axis.values.filter((value) => drawn.includes(value));
|
|
3951
|
-
const variants2 = current.variants.filter((v) => values.includes(v.props[axis.name]));
|
|
3952
|
-
const covered = new Set(variants2.filter((v) => v.props[axis.name] === axis.default).map(others));
|
|
3953
|
-
for (const v of current.variants) {
|
|
3954
|
-
if (values.includes(v.props[axis.name]) || covered.has(others(v))) continue;
|
|
3955
|
-
covered.add(others(v));
|
|
3956
|
-
variants2.push({ ...v, props: { ...v.props, [axis.name]: axis.default } });
|
|
3957
|
-
}
|
|
3958
|
-
if (values.length > 1) current = { axes: current.axes.map((a2) => a2 === axis ? { ...a2, values } : a2), variants: variants2 };
|
|
3959
|
-
else
|
|
3960
|
-
current = {
|
|
3961
|
-
axes: current.axes.filter((a2) => a2 !== axis),
|
|
3962
|
-
variants: variants2.map((v) => ({ ...v, props: Object.fromEntries(Object.entries(v.props).filter(([k]) => k !== axis.name)) }))
|
|
3963
|
-
};
|
|
3964
|
-
}
|
|
3965
|
-
return current;
|
|
4544
|
+
function describePartFix(f) {
|
|
4545
|
+
if (f.hide) return `${f.part} hidden`;
|
|
4546
|
+
const bits = [
|
|
4547
|
+
...Object.entries(f.set ?? {}).map(([k, v]) => `${k} ${v === null ? "none" : String(v)}`),
|
|
4548
|
+
...f.width !== void 0 ? [`width ${String(f.width)}`] : [],
|
|
4549
|
+
...f.height !== void 0 ? [`height ${String(f.height)}`] : [],
|
|
4550
|
+
...f.direction ? [`direction ${f.direction}`] : [],
|
|
4551
|
+
...f.align ? [`align ${[f.align.primary, f.align.counter].filter(Boolean).join(" ")}`] : [],
|
|
4552
|
+
...f.overlay !== void 0 ? [`overlay ${typeof f.overlay === "boolean" ? String(f.overlay) : JSON.stringify(f.overlay)}`] : []
|
|
4553
|
+
];
|
|
4554
|
+
return `${f.part}: ${bits.join(", ")}`;
|
|
3966
4555
|
}
|
|
3967
|
-
function
|
|
3968
|
-
|
|
3969
|
-
const key2 = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
3970
|
-
const only = opts.only === void 0 ? void 0 : key2(opts.only);
|
|
3971
|
-
const groups = /* @__PURE__ */ new Map();
|
|
3972
|
-
for (const s of file.stories) {
|
|
3973
|
-
if (s.error || !s.spec) continue;
|
|
3974
|
-
const name = setNameOf$1(s.title);
|
|
3975
|
-
if (only !== void 0 && key2(name) !== only) continue;
|
|
3976
|
-
groups.set(name, [...groups.get(name) ?? [], s]);
|
|
3977
|
-
}
|
|
3978
|
-
const argTypesOf = (name) => Object.assign({}, ...(file.components ?? []).filter((c) => setNameOf$1(c.title) === name).map((c) => c.argTypes));
|
|
3979
|
-
const hints = {};
|
|
3980
|
-
for (const c of file.components ?? []) if (c.figma) hints[setNameOf$1(c.title)] = { ...hints[setNameOf$1(c.title)], ...c.figma };
|
|
3981
|
-
const components = [];
|
|
3982
|
-
const shots = {};
|
|
3983
|
-
const report = { sets: 0, variants: 0, stories: 0, skipped: [] };
|
|
3984
|
-
for (const [name, stories] of [...groups].sort(([a2], [b]) => a2.localeCompare(b))) {
|
|
3985
|
-
const built = setOf(name, stories, argTypesOf(name), file.storybook, known, hints[name]);
|
|
3986
|
-
if (!built) {
|
|
3987
|
-
report.skipped.push(name);
|
|
3988
|
-
continue;
|
|
3989
|
-
}
|
|
3990
|
-
const spec = built.spec;
|
|
3991
|
-
components.push(spec);
|
|
3992
|
-
if (Object.keys(built.shots).length) shots[name] = built.shots;
|
|
3993
|
-
report.sets++;
|
|
3994
|
-
report.variants += spec.variants.length;
|
|
3995
|
-
report.stories += stories.length;
|
|
3996
|
-
}
|
|
3997
|
-
return { specs: { version: 1, generated: `Measured from ${file.storybook} on ${file.measuredAt} (bridge specs --measure).`, components }, report, shots, hints };
|
|
4556
|
+
function appliedFixLines(applied) {
|
|
4557
|
+
return applied.map((a2) => `${a2.result === "applied" ? "applied" : a2.result === "already" ? "already applied" : a2.result === "skipped" ? "skipped" : "not found"} ${a2.id} (${a2.component}, ${a2.kind}): ${a2.detail}`);
|
|
3998
4558
|
}
|
|
3999
4559
|
const DEFAULT_FIDELITY_RUN_FILE = "figma-fidelity.json";
|
|
4000
4560
|
const FIX_LOOP_MAX_ROUNDS = 3;
|
|
@@ -4082,7 +4642,7 @@ function gapCaseFor(input) {
|
|
|
4082
4642
|
}
|
|
4083
4643
|
const FIX_SCHEMA_SUMMARY = `figma-fixes.json fixes (version ${FIGMA_FIXES_VERSION}). Each fix is one JSON object:
|
|
4084
4644
|
- Every fix: "id" (lower case, digits, dashes, unique), "kind", "component" (the Figma set, e.g. "TextInput"), "reason" (one plain sentence, no em dash), optional "by": "claude", optional "where": { "args": { "<arg>": value }, "state": "rest" | "hover" | "active" | "focus-visible" | "disabled" } (absent: every variant).
|
|
4085
|
-
- kind "part": "part" is a part id from the gap case ("root", "cds--text-input-label-wrapper") or ".class". At least one of: "set" { field: token path | px number | null (colors only) | "full" (cornerRadius only) }, "width" / "height": "fixed" (
|
|
4645
|
+
- kind "part": "part" is a part id from the gap case ("root", "cds--text-input-label-wrapper") or ".class". At least one of: "set" { field: token path | px number | null (colors only) | "full" (cornerRadius only) }, "width" / "height": "fixed" (each story's own measured size; a width that only hugs text in code is skipped, since it is the story's words) | px number | "hug" | "fill", "direction": "HORIZONTAL" | "VERTICAL", "align": { "primary": MIN|CENTER|MAX|SPACE_BETWEEN, "counter": MIN|CENTER|MAX|STRETCH }, "overlay": true | false | { "top": 3, "left": 3 }, "hide": true (alone; never the root). Fields: fill, stroke, strokeWeight, strokeTopWeight, strokeRightWeight, strokeBottomWeight, strokeLeftWeight, cornerRadius, paddingTop, paddingRight, paddingBottom, paddingLeft, itemSpacing, counterAxisSpacing, width, height, minWidth, minHeight, opacity, textFill, fontFamily, fontSize, fontWeight, lineHeight, letterSpacing, textDecoration.
|
|
4086
4646
|
- kind "axis": "action" "map" ("arg", "property" and/or "values" { code value: Figma value }), "ignore" ("arg"), or "prune" ("where" names the variants to drop).
|
|
4087
4647
|
- kind "story": "where" names the variant, "use": { "story": "<story id>", "args"?, "state"? } is the measured render to draw it from.
|
|
4088
4648
|
- kind "status": "status": "differs" | "cant-check" with the reason; never "matches" (only the shots say a component matches). Without "status": a note.
|
|
@@ -4136,16 +4696,16 @@ function tryFigmaFixes(input) {
|
|
|
4136
4696
|
const stories = storiesOfComponent(before.measured, component);
|
|
4137
4697
|
const variants = [];
|
|
4138
4698
|
for (const gv of before.gap.variants) {
|
|
4139
|
-
const vb = before.spec
|
|
4140
|
-
const want = before.spec ? renamedProps(gv.props, before.spec, afterSpec, hintsB, hintsA) : gv.props;
|
|
4141
|
-
const va = afterSpec
|
|
4699
|
+
const vb = matchVariant(before.spec, gv.props);
|
|
4700
|
+
const want = before.spec ? renamedProps(vb?.props ?? gv.props, before.spec, afterSpec, hintsB, hintsA) : gv.props;
|
|
4701
|
+
const va = matchVariant(afterSpec, gv.props) ?? matchVariant(afterSpec, want);
|
|
4142
4702
|
if (!va || !afterSpec) {
|
|
4143
4703
|
variants.push({ key: gv.key, ...gv.story ? { story: gv.story.id } : {}, verdict: "gone", differences: [], regressions: [] });
|
|
4144
4704
|
continue;
|
|
4145
4705
|
}
|
|
4146
4706
|
const differences = gv.differences.map((d) => tryDifference(d, before.spec, vb, afterSpec, va, built?.[gv.key], resolve2));
|
|
4147
4707
|
let regressions2 = [];
|
|
4148
|
-
const story = before.spec ? storyForVariant(before.spec, gv.props, stories, before.shots[gv.key]) : void 0;
|
|
4708
|
+
const story = before.spec ? storyForVariant(before.spec, gv.props, stories, before.shots[gv.key] ?? (vb ? before.shots[variantKeyOf(vb.props)] : void 0)) : void 0;
|
|
4149
4709
|
const m = story ? story.instances?.[0] ?? story.spec : void 0;
|
|
4150
4710
|
if (m && before.spec && vb) {
|
|
4151
4711
|
const key2 = (d) => `${d.part}|${d.property}`;
|
|
@@ -4158,7 +4718,7 @@ function tryFigmaFixes(input) {
|
|
|
4158
4718
|
const all = variants.flatMap((v) => v.differences);
|
|
4159
4719
|
const regressions = variants.reduce((n, v) => n + v.regressions.length, 0);
|
|
4160
4720
|
const verdict = verdictOf(all, variants.flatMap((v) => v.regressions));
|
|
4161
|
-
const notFound = applied.filter((a2) => a2.result === "not-found");
|
|
4721
|
+
const notFound = applied.filter((a2) => a2.result === "not-found" || a2.result === "skipped");
|
|
4162
4722
|
return {
|
|
4163
4723
|
status: "checked",
|
|
4164
4724
|
component,
|
|
@@ -4172,7 +4732,6 @@ function tryFigmaFixes(input) {
|
|
|
4172
4732
|
file
|
|
4173
4733
|
};
|
|
4174
4734
|
}
|
|
4175
|
-
const sameProps = (a2, b) => Object.keys(a2).length === Object.keys(b).length && Object.entries(a2).every(([k, v]) => b[k] === v);
|
|
4176
4735
|
function renamedProps(props, specB, specA, hintsB, hintsA) {
|
|
4177
4736
|
const out = {};
|
|
4178
4737
|
for (const [name, value] of Object.entries(props)) {
|
|
@@ -4303,7 +4862,9 @@ function sizeShift(field, specB, vb, specA, va, built, resolve2) {
|
|
|
4303
4862
|
}
|
|
4304
4863
|
function trySummary(component, gap, diffs, regressions, verdict, notFound, proposed, gone) {
|
|
4305
4864
|
if (!gap.variants.length) return `${component} has no differing variant in the gap case: nothing for these fixes to move (the values referee needs a Check fidelity report or a difference in the measure).`;
|
|
4306
|
-
const
|
|
4865
|
+
const missing = notFound.filter((a2) => a2.result === "not-found");
|
|
4866
|
+
const skipped = notFound.filter((a2) => a2.result === "skipped");
|
|
4867
|
+
const absent = (missing.length ? ` ${missing.map((a2) => a2.id).join(", ")} found nothing in the measure.` : "") + (skipped.length ? ` ${skipped.map((a2) => a2.id).join(", ")} laid nothing on: the measure has no size of the part's own to fix it at (see the detail).` : "");
|
|
4307
4868
|
if (!diffs.length && gone) {
|
|
4308
4869
|
const n = gap.variants.length;
|
|
4309
4870
|
const which = gone < n ? `${gone} of the ${n} differing variants are not` : n === 1 ? "the differing variant is not" : `none of the ${n} differing variants is`;
|
|
@@ -5120,192 +5681,6 @@ async function readCombineBranch(gh, pull, opts) {
|
|
|
5120
5681
|
);
|
|
5121
5682
|
return { number: pull.number, title: pull.title, tokens: true, edits: changeEdits(source) };
|
|
5122
5683
|
}
|
|
5123
|
-
const PRODUCT_FILE = /\.(css|scss|sass|less|tsx|jsx|ts|js|mjs|cjs|mts|cts|astro|vue|svelte)$/;
|
|
5124
|
-
const SKIP_FILE = /\.d\.[cm]?ts$|\.(test|spec|stories|story)\.[cm]?[jt]sx?$|\.min\.(css|js)$/;
|
|
5125
|
-
const PIECES_FILE_LIMIT = 40;
|
|
5126
|
-
const cleanPath = (p2) => p2.trim().replace(/^\.?\/+|\/+$/g, "");
|
|
5127
|
-
function productOf(products, pull, files) {
|
|
5128
|
-
const product = productOfBranch(products, { labels: pull.labels, files });
|
|
5129
|
-
if (product.key === defaultProduct(products).key) throw new GitHubError(422, `This branch is a library branch (${product.name}), not a product branch: missing pieces are checked on a branch started for a product.`);
|
|
5130
|
-
return product;
|
|
5131
|
-
}
|
|
5132
|
-
async function readProductBranchOnGitHub(gh, pr, opts) {
|
|
5133
|
-
const pull = await gh.getPullRequest(pr);
|
|
5134
|
-
const cmp = await gh.compareDetailed(pull.baseRef, pull.headSha);
|
|
5135
|
-
const product = productOf(opts.products, pull, cmp.files.map((f) => f.filename));
|
|
5136
|
-
const dir = product.path ? `${cleanPath(product.path)}/` : "";
|
|
5137
|
-
const changed = cmp.files.filter((f) => f.status !== "removed" && (!dir || f.filename.startsWith(dir)) && PRODUCT_FILE.test(f.filename) && !SKIP_FILE.test(f.filename) && !f.filename.split("/").includes("node_modules"));
|
|
5138
|
-
const read = changed.slice(0, PIECES_FILE_LIMIT);
|
|
5139
|
-
const start = cmp.mergeBase ?? pull.baseRef;
|
|
5140
|
-
const files = await Promise.all(
|
|
5141
|
-
read.map(async (f) => {
|
|
5142
|
-
const [before, after] = await Promise.all([f.status === "added" ? Promise.resolve(void 0) : gh.getFileText(f.previous_filename ?? f.filename, start), gh.getFileText(f.filename, pull.headSha)]);
|
|
5143
|
-
return { path: f.filename, before: before ?? null, after: after ?? null };
|
|
5144
|
-
})
|
|
5145
|
-
);
|
|
5146
|
-
return { pull, product, files, skipped: changed.length - read.length, record: parsePiecesRecord(pull.body) };
|
|
5147
|
-
}
|
|
5148
|
-
async function recordPiecesOnGitHub(gh, pr, check) {
|
|
5149
|
-
const pull = await gh.getPullRequest(pr);
|
|
5150
|
-
const record = mergePiecesRecord(parsePiecesRecord(pull.body), { checkedAt: check.checkedAt ?? (/* @__PURE__ */ new Date()).toISOString(), headSha: check.headSha ?? pull.headSha, pieces: check.pieces, fixes: check.fixes });
|
|
5151
|
-
await gh.updatePullRequest(pr, { body: withPiecesRecord(pull.body, record) });
|
|
5152
|
-
return record;
|
|
5153
|
-
}
|
|
5154
|
-
const productWriter = (gh, branch) => isExplorationBranch(branch) ? gh.withBranchPrefix(EXPLORATION_PREFIX) : gh;
|
|
5155
|
-
async function useLibraryPreviewOnGitHub(gh, input) {
|
|
5156
|
-
const message = `chore(bridge): use the preview of ${input.libraryBranch} (#${input.libraryNumber})
|
|
5157
|
-
|
|
5158
|
-
The product branch takes the library branch before it ships. Switch to the published version once it does.`;
|
|
5159
|
-
try {
|
|
5160
|
-
const r = await productWriter(gh, input.productBranch).mergeIntoBranch(input.productBranch, input.libraryBranch, message);
|
|
5161
|
-
return { ...r, said: r.status === "merged" ? "Your branch now uses the preview of the library branch." : "Your branch already has the latest preview." };
|
|
5162
|
-
} catch (err) {
|
|
5163
|
-
if (err instanceof GitHubError && err.status === 409) return { status: "conflict", sha: null, said: `Your branch and the library branch change the same lines. A developer merges ${input.libraryBranch} into ${input.productBranch} by hand.` };
|
|
5164
|
-
throw err;
|
|
5165
|
-
}
|
|
5166
|
-
}
|
|
5167
|
-
function productBranchRef(pull, product) {
|
|
5168
|
-
const name = /<!-- bridge-exploration (\{[\s\S]*?\}) -->/.exec(pull.body ?? "");
|
|
5169
|
-
let title = pull.title.replace(/^[A-Z][A-Z0-9_]*-\d+\s+/, "").replace(/^Exploration:\s*/i, "");
|
|
5170
|
-
let author = pull.author;
|
|
5171
|
-
if (name) {
|
|
5172
|
-
try {
|
|
5173
|
-
const e = JSON.parse(name[1]);
|
|
5174
|
-
if (e.name) title = e.name;
|
|
5175
|
-
if (e.author) author = e.author;
|
|
5176
|
-
} catch {
|
|
5177
|
-
}
|
|
5178
|
-
}
|
|
5179
|
-
return { pr: pull.number, title: title.charAt(0).toUpperCase() + title.slice(1), branch: pull.headRef, url: pull.url, productKey: product.key, productName: product.name, ...author ? { author } : {} };
|
|
5180
|
-
}
|
|
5181
|
-
async function openLibraryBranchOnGitHub(gh, input) {
|
|
5182
|
-
const pull = await gh.getPullRequest(input.pr);
|
|
5183
|
-
const record = parsePiecesRecord(pull.body);
|
|
5184
|
-
const piece = record?.pieces.find((p2) => p2.id === input.piece);
|
|
5185
|
-
if (!record || !piece) throw new GitHubError(404, record ? `No piece "${input.piece}" on #${input.pr}. Pieces: ${record.pieces.map((p2) => p2.id).join(", ") || "none"}.` : `#${input.pr} was not checked yet: find its missing pieces first (bridge_missing_pieces with record, or \`bridge pieces ${input.pr} --record\`).`);
|
|
5186
|
-
const product = productOf(input.products, pull, await gh.listPullRequestFiles(input.pr).then((f) => f.map((x) => x.filename), () => []));
|
|
5187
|
-
const mode = input.mode ?? "direct";
|
|
5188
|
-
const plan = libraryBranchPlan(piece, productBranchRef(pull, product), { source: input.source, requestedBy: input.openedBy, mode });
|
|
5189
|
-
const existing = record.links.find((l) => l.piece === piece.id);
|
|
5190
|
-
if (existing) return { status: "already-linked", plan, link: existing, preview: null, warnings: [] };
|
|
5191
|
-
if (input.dryRun) return { status: "dry-run", plan, link: null, preview: null, warnings: [] };
|
|
5192
|
-
if (!gh.canWrite) throw new GitHubError(401, mode === "suggest" ? "Suggesting a library change needs a GitHub token (issues: write)." : "Opening a library branch needs a GitHub token (contents, pull requests and issues: write).");
|
|
5193
|
-
const warnings = [];
|
|
5194
|
-
const at2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
5195
|
-
const who = { ...input.openedBy ? { openedBy: input.openedBy } : {}, ...input.agent ? { agent: input.agent } : {} };
|
|
5196
|
-
let link;
|
|
5197
|
-
if (plan.kind === "token-change") {
|
|
5198
|
-
if (!input.writeTokens) throw new GitHubError(422, "This piece is a token: open it where the token files are read (Bridge Studio, bridge_open_library_branch or `bridge pieces open`).");
|
|
5199
|
-
const r = await input.writeTokens(plan, { mode });
|
|
5200
|
-
link = r.status === "suggested" ? { piece: piece.id, kind: "suggestion", number: r.number, url: r.url, title: plan.title, at: at2, ...who } : { piece: piece.id, kind: "token-change", number: r.number, url: r.url, title: plan.title, branch: r.branch, at: at2, ...who };
|
|
5201
|
-
} else if (plan.kind === "exploration") {
|
|
5202
|
-
const r = await startExplorationOnGitHub(gh, { ...plan.exploration, ...input.openedBy ? { author: input.openedBy } : {}, ...input.agent ? { agent: input.agent } : {} }, { base: input.base, ...input.exploration, labels: [NEEDED_BY_LABEL] });
|
|
5203
|
-
link = { piece: piece.id, kind: "exploration", number: r.pr, url: r.url, title: plan.title, branch: r.branch, at: at2, ...who };
|
|
5204
|
-
} else {
|
|
5205
|
-
const issue = composeRequestIssue(plan.request, { labels: [NEEDED_BY_LABEL] });
|
|
5206
|
-
const r = await gh.createIssue(issue);
|
|
5207
|
-
link = { piece: piece.id, kind: "request", number: r.number, url: r.url, title: plan.title, at: at2, ...who };
|
|
5208
|
-
}
|
|
5209
|
-
try {
|
|
5210
|
-
if (link.kind === "request" || link.kind === "suggestion") {
|
|
5211
|
-
const issue = await gh.getIssue(link.number);
|
|
5212
|
-
await gh.updateIssue(link.number, { body: withNeededBy(issue.body, plan.neededBy) });
|
|
5213
|
-
if (link.kind === "suggestion" && !issue.labels.includes(NEEDED_BY_LABEL)) await gh.addLabels(link.number, [NEEDED_BY_LABEL]);
|
|
5214
|
-
} else {
|
|
5215
|
-
const lib = await gh.getPullRequest(link.number);
|
|
5216
|
-
await gh.updatePullRequest(link.number, { body: withNeededBy(lib.body, plan.neededBy) });
|
|
5217
|
-
await gh.addLabels(link.number, [NEEDED_BY_LABEL]);
|
|
5218
|
-
}
|
|
5219
|
-
} catch (err) {
|
|
5220
|
-
if (err instanceof GitHubError && err.auth === "rejected") throw err;
|
|
5221
|
-
warnings.push(`The library side does not say who needs it yet (${err.message}). Add "Needed by #${input.pr}" to #${link.number} on GitHub.`);
|
|
5222
|
-
}
|
|
5223
|
-
try {
|
|
5224
|
-
const fresh = await gh.getPullRequest(input.pr);
|
|
5225
|
-
const next = withLink(parsePiecesRecord(fresh.body) ?? record, link);
|
|
5226
|
-
await gh.updatePullRequest(input.pr, { body: withPiecesRecord(fresh.body, next) });
|
|
5227
|
-
} catch (err) {
|
|
5228
|
-
if (mode !== "suggest") throw err;
|
|
5229
|
-
warnings.push(`#${input.pr} does not list #${link.number} yet (${err.message}). Add "Library: #${link.number}" to #${input.pr} on GitHub, so this piece is not sent twice.`);
|
|
5230
|
-
}
|
|
5231
|
-
let preview = null;
|
|
5232
|
-
if ((input.usePreview ?? true) && link.kind === "token-change" && link.branch) {
|
|
5233
|
-
preview = await useLibraryPreviewOnGitHub(gh, { productBranch: pull.headRef, libraryBranch: link.branch, libraryNumber: link.number }).catch((err) => {
|
|
5234
|
-
warnings.push(`Your branch does not use the preview yet: ${err.message}`);
|
|
5235
|
-
return null;
|
|
5236
|
-
});
|
|
5237
|
-
}
|
|
5238
|
-
return { status: link.kind === "suggestion" ? "suggested" : "opened", plan, link, preview, warnings };
|
|
5239
|
-
}
|
|
5240
|
-
const isNote = (path) => path.startsWith(`${EXPLORATION_NOTES_DIR}/`);
|
|
5241
|
-
async function linkedLibraryBranchOnGitHub(gh, link, product, piece) {
|
|
5242
|
-
const nearest = piece?.nearest?.label;
|
|
5243
|
-
if (link.kind === "suggestion") {
|
|
5244
|
-
const issue = await gh.getIssue(link.number);
|
|
5245
|
-
const cached = suggestionStateFromLabels(issue.labels);
|
|
5246
|
-
const s = suggestionStatus({ state: issue.state, stateReason: issue.stateReason, applied: cached === "applying", review: cached === "applying" ? void 0 : cached });
|
|
5247
|
-
const status2 = linkStatus({ kind: "suggestion", status: s });
|
|
5248
|
-
const lifecycle2 = s === "applied" ? "merged" : issue.state === "closed" ? "closed" : "open";
|
|
5249
|
-
const behindMain2 = lifecycle2 === "merged" ? await gh.compare(product.baseRef, product.headSha).then((c) => c.behindBy, () => null) : null;
|
|
5250
|
-
const preview2 = libraryPreviewState({ kind: "suggestion", lifecycle: lifecycle2, hasChanges: false, missing: null, total: null, behindMain: behindMain2, nearest });
|
|
5251
|
-
return { link, piece, status: status2, preview: preview2, people: status2.people };
|
|
5252
|
-
}
|
|
5253
|
-
if (link.kind === "request") {
|
|
5254
|
-
const issue = await gh.getIssue(link.number);
|
|
5255
|
-
const status2 = linkStatus({ kind: "request", state: issue.state, stateReason: issue.stateReason });
|
|
5256
|
-
const lifecycle2 = issue.state === "closed" ? issue.stateReason === "not_planned" ? "closed" : "merged" : "open";
|
|
5257
|
-
const behindMain2 = lifecycle2 === "merged" ? await gh.compare(product.baseRef, product.headSha).then((c) => c.behindBy, () => null) : null;
|
|
5258
|
-
const preview2 = libraryPreviewState({ kind: "request", lifecycle: lifecycle2, hasChanges: false, missing: null, total: null, behindMain: behindMain2, nearest });
|
|
5259
|
-
return { link, piece, status: status2, preview: preview2, people: status2.people };
|
|
5260
|
-
}
|
|
5261
|
-
const lib = await gh.getPullRequest(link.number);
|
|
5262
|
-
const reviews = await gh.listReviews(link.number).catch(() => []);
|
|
5263
|
-
const status = linkStatus({ kind: link.kind, state: lib.state, draft: lib.draft, labels: lib.labels, requestedReviewers: lib.requestedReviewers, reviews: reviews.map((r) => ({ user: r.user, state: r.state })) });
|
|
5264
|
-
const lifecycle = lib.state === "merged" ? "merged" : lib.state === "open" ? "open" : "closed";
|
|
5265
|
-
let missing = null;
|
|
5266
|
-
let total = null;
|
|
5267
|
-
let behindMain = null;
|
|
5268
|
-
let hasChanges = true;
|
|
5269
|
-
if (lifecycle === "open") {
|
|
5270
|
-
const [files, own, inProduct] = await Promise.all([
|
|
5271
|
-
gh.listPullRequestFiles(link.number).catch(() => null),
|
|
5272
|
-
gh.compare(lib.baseRef, lib.headSha).catch(() => null),
|
|
5273
|
-
gh.compare(product.headSha, lib.headSha).catch(() => null)
|
|
5274
|
-
]);
|
|
5275
|
-
hasChanges = files ? files.some((f) => !isNote(f.filename)) : true;
|
|
5276
|
-
total = own?.aheadBy ?? null;
|
|
5277
|
-
missing = inProduct?.aheadBy ?? null;
|
|
5278
|
-
} else if (lifecycle === "merged") {
|
|
5279
|
-
behindMain = await gh.compare(product.baseRef, product.headSha).then((c) => c.behindBy, () => null);
|
|
5280
|
-
}
|
|
5281
|
-
const preview = libraryPreviewState({ kind: link.kind, lifecycle, hasChanges, missing, total, behindMain, nearest });
|
|
5282
|
-
return { link, piece, status, preview, people: status.people };
|
|
5283
|
-
}
|
|
5284
|
-
async function productBranchViewOnGitHub(gh, pr, opts) {
|
|
5285
|
-
const pull = await gh.getPullRequest(pr);
|
|
5286
|
-
const files = await gh.listPullRequestFiles(pr).then((f) => f.map((x) => x.filename), () => []);
|
|
5287
|
-
const product = productOf(opts.products, pull, files);
|
|
5288
|
-
const record = parsePiecesRecord(pull.body);
|
|
5289
|
-
const linked = await Promise.all(
|
|
5290
|
-
(record?.links ?? []).map((l) => linkedLibraryBranchOnGitHub(gh, l, { headSha: pull.headSha, baseRef: pull.baseRef }, record?.pieces.find((p2) => p2.id === l.piece)))
|
|
5291
|
-
);
|
|
5292
|
-
const open = (record?.pieces ?? []).filter((p2) => !record.links.some((l) => l.piece === p2.id));
|
|
5293
|
-
return { pull, product, record, sentence: productBranchSentence(record, { viewer: opts.viewer, agentName: opts.agentName }), linked, open };
|
|
5294
|
-
}
|
|
5295
|
-
async function switchToPublishedOnGitHub(gh, pr) {
|
|
5296
|
-
if (!gh.canWrite) throw new GitHubError(401, "Switching needs a GitHub token (contents and pull requests: write).");
|
|
5297
|
-
const pull = await gh.getPullRequest(pr);
|
|
5298
|
-
if (pull.state !== "open") throw new GitHubError(422, `#${pr} is ${pull.state}: only an open branch switches.`);
|
|
5299
|
-
const cmp = await gh.compare(pull.baseRef, pull.headSha);
|
|
5300
|
-
if (cmp.behindBy === 0) return { status: "up-to-date", said: "Your branch already uses the published version." };
|
|
5301
|
-
try {
|
|
5302
|
-
await gh.updatePullRequestBranch(pr, pull.headSha);
|
|
5303
|
-
} catch (err) {
|
|
5304
|
-
if (err instanceof GitHubError && err.status === 422) throw new GitHubError(422, `Your branch and ${pull.baseRef} change the same lines, so Bridge cannot switch it alone. Use "Update from main" to pick the token values, or ask a developer.`, err.detail);
|
|
5305
|
-
throw err;
|
|
5306
|
-
}
|
|
5307
|
-
return { status: "switched", said: `Your branch now uses the published version from ${pull.baseRef}.` };
|
|
5308
|
-
}
|
|
5309
5684
|
const issueKey = (i) => `${i.code}|${i.path ?? ""}|${i.file ?? ""}|${i.message}`;
|
|
5310
5685
|
function planTokenProposal(input) {
|
|
5311
5686
|
const { before, config } = input;
|
|
@@ -6507,14 +6882,14 @@ const semverDesc = (a2, b) => {
|
|
|
6507
6882
|
for (let i = 0; i < 3; i++) if (pa[i] !== pb[i]) return pb[i] - pa[i];
|
|
6508
6883
|
return 0;
|
|
6509
6884
|
};
|
|
6510
|
-
function groupReleases(sections,
|
|
6885
|
+
function groupReleases(sections, dateOf2, libraryPackage = "@bridge-ds/react") {
|
|
6511
6886
|
const all = sections;
|
|
6512
6887
|
const parent = all.map((_, i) => i);
|
|
6513
6888
|
const find = (i) => parent[i] === i ? i : parent[i] = find(parent[i]);
|
|
6514
6889
|
const union = (a2, b) => {
|
|
6515
6890
|
parent[find(a2)] = find(b);
|
|
6516
6891
|
};
|
|
6517
|
-
const dates = all.map((s) =>
|
|
6892
|
+
const dates = all.map((s) => dateOf2(s.pkg, s.version));
|
|
6518
6893
|
const byKey = /* @__PURE__ */ new Map();
|
|
6519
6894
|
all.forEach((s, i) => {
|
|
6520
6895
|
const keys = [...dates[i] ? [`d:${dates[i]}`] : [], ...s.notes.map((n) => `n:${n.id}`)];
|
|
@@ -7770,8 +8145,8 @@ async function libraryArrivalOnGitHub(gh, n) {
|
|
|
7770
8145
|
return libraryArrival({ state: pr.state, mergeable: pr.mergeable, ci: ci3, changesRequested: approvals.changesRequested.length });
|
|
7771
8146
|
}
|
|
7772
8147
|
export {
|
|
7773
|
-
|
|
7774
|
-
|
|
8148
|
+
ar as AAA_MIN,
|
|
8149
|
+
as as AA_MIN,
|
|
7775
8150
|
ACTIVITY_FILE,
|
|
7776
8151
|
ACTIVITY_LIMITS,
|
|
7777
8152
|
ACTIVITY_MAX_AGE_MS,
|
|
@@ -7791,40 +8166,41 @@ export {
|
|
|
7791
8166
|
BUILD_STALE_DAYS,
|
|
7792
8167
|
BUILD_STATUS_LABEL,
|
|
7793
8168
|
BUILD_STEPS,
|
|
7794
|
-
|
|
8169
|
+
aL2 as BULK_LIMIT,
|
|
7795
8170
|
CANT_CHECK_COPY,
|
|
7796
8171
|
CHANGELOG_DETAIL_MAX,
|
|
7797
|
-
|
|
7798
|
-
|
|
8172
|
+
at as CHANGES_MODES,
|
|
8173
|
+
aM2 as CI_STATE_LABEL,
|
|
7799
8174
|
COLOR_FIELDS,
|
|
7800
8175
|
COMBINE_COMPARE_LIMIT,
|
|
7801
8176
|
COMPARE_FILE_LIMIT,
|
|
7802
|
-
|
|
8177
|
+
aN2 as COMPONENT_SPECS_VERSION,
|
|
7803
8178
|
CONFIG_FILE,
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
8179
|
+
aO2 as CONFLICT_REASON,
|
|
8180
|
+
CONTINUE_PHRASE,
|
|
8181
|
+
au as CONTRAST_CELL_MAX,
|
|
8182
|
+
av as CONTRAST_CHECKS_FILE,
|
|
7807
8183
|
CONTRAST_THRESHOLDS,
|
|
7808
8184
|
ConfigError,
|
|
7809
8185
|
DEFAULT_CHANGES_MODE,
|
|
7810
|
-
|
|
8186
|
+
aP2 as DEFAULT_COMPONENT_SPECS_FILE,
|
|
7811
8187
|
DEFAULT_FIDELITY_RUN_FILE,
|
|
7812
8188
|
DEFAULT_FIGMA_FIXES_FILE,
|
|
7813
|
-
|
|
8189
|
+
aw as DEFAULT_GOVERNANCE,
|
|
7814
8190
|
DEFAULT_MEASURED_SPECS_FILE,
|
|
7815
8191
|
DEFAULT_OVERRIDE,
|
|
7816
8192
|
DEFAULT_PRODUCTS,
|
|
7817
|
-
|
|
7818
|
-
|
|
8193
|
+
aQ2 as DEFAULT_PROTECTED_BRANCHES,
|
|
8194
|
+
ax as DEFAULT_RIGHTS,
|
|
7819
8195
|
DEFAULT_TOKEN_PATHS,
|
|
7820
|
-
|
|
8196
|
+
ay as DEFAULT_VISUAL_IMPACT,
|
|
7821
8197
|
DEMO_RELEASES,
|
|
7822
|
-
|
|
7823
|
-
|
|
8198
|
+
aR2 as DOCS_CHANGE_BUMP,
|
|
8199
|
+
aS2 as DOCS_CLI_ORIGIN,
|
|
7824
8200
|
DOCS_DRAFT_MODEL,
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
8201
|
+
aT2 as DOCS_EDITOR_ORIGIN,
|
|
8202
|
+
aU2 as DOCS_KEYS,
|
|
8203
|
+
aV2 as DOCS_MCP_ORIGIN,
|
|
7828
8204
|
DOCS_SELECTION_MODES,
|
|
7829
8205
|
DRAFTED_BY_CLAUDE_LABEL,
|
|
7830
8206
|
DRAFTS_DIR,
|
|
@@ -7837,15 +8213,19 @@ export {
|
|
|
7837
8213
|
DRAFT_SUMMARY_SENTENCES,
|
|
7838
8214
|
DRAFT_TITLE_MAX,
|
|
7839
8215
|
DRAFT_VOICE_RULES,
|
|
7840
|
-
|
|
8216
|
+
az as DTCG_TYPES,
|
|
7841
8217
|
DraftPoller,
|
|
7842
|
-
|
|
8218
|
+
EXPLORATION_ARCHIVED_LABEL,
|
|
8219
|
+
aW2 as EXPLORATION_CHECK,
|
|
7843
8220
|
EXPLORATION_LABEL,
|
|
7844
8221
|
EXPLORATION_NOTES_DIR,
|
|
7845
8222
|
EXPLORATION_PREFIX,
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
8223
|
+
aX2 as EXPLORATION_READY_LABEL,
|
|
8224
|
+
aY2 as EXPLORATION_SLUG_MAX,
|
|
8225
|
+
aZ2 as EXPLORATION_STARTING_POINT,
|
|
8226
|
+
a_2 as EXPLORATION_STATUS_LABEL,
|
|
8227
|
+
a$2 as EXPLORATION_TIER_LABEL,
|
|
8228
|
+
b02 as EXPLORATION_USE_CASES,
|
|
7849
8229
|
EXT_ID,
|
|
7850
8230
|
EXT_SCOPES,
|
|
7851
8231
|
FIDELITY_DEFAULTS,
|
|
@@ -7861,18 +8241,18 @@ export {
|
|
|
7861
8241
|
FIX_LOOP_MAX_ROUNDS,
|
|
7862
8242
|
FIX_LOOP_MODEL,
|
|
7863
8243
|
FIX_SCHEMA_SUMMARY,
|
|
7864
|
-
|
|
8244
|
+
b12 as FORMER_MEMBER,
|
|
7865
8245
|
FROM_FIGMA_LABEL,
|
|
7866
8246
|
FigmaFixesError,
|
|
7867
8247
|
GAP_CASE_VERSION,
|
|
7868
8248
|
GitHubClient,
|
|
7869
8249
|
GitHubError,
|
|
7870
8250
|
HISTORY_MAX_CHANGES,
|
|
7871
|
-
|
|
8251
|
+
aA as JsonParseError,
|
|
7872
8252
|
LIGHTNESS,
|
|
7873
|
-
|
|
8253
|
+
aB as LINK_STATUS_TONE,
|
|
7874
8254
|
LLMS_MAX_TOKENS,
|
|
7875
|
-
|
|
8255
|
+
b22 as LOOK_AGAIN_STATUS_LABEL,
|
|
7876
8256
|
LayeredTokenSet,
|
|
7877
8257
|
MAX_TOGETHER,
|
|
7878
8258
|
MEASURED_SHOTS_DIR,
|
|
@@ -7886,39 +8266,39 @@ export {
|
|
|
7886
8266
|
MEASURE_WORKFLOW_HEADER,
|
|
7887
8267
|
MIN_TOGETHER,
|
|
7888
8268
|
MeasureMissingError,
|
|
7889
|
-
|
|
8269
|
+
b32 as MeasuredSpecsError,
|
|
7890
8270
|
NEEDED_BY_LABEL,
|
|
7891
8271
|
NEUTRAL_ANCHORS,
|
|
7892
8272
|
OVERRIDE_HEADING,
|
|
7893
|
-
|
|
8273
|
+
aC as OWNER_GROUPS,
|
|
7894
8274
|
OverrideMergeError,
|
|
7895
8275
|
PIECES_FILE_LIMIT,
|
|
7896
8276
|
PIN_TOLERANCE,
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
8277
|
+
aD as PREVIEW_APP_LABELS,
|
|
8278
|
+
aE as PREVIEW_COMMENT_MARKER,
|
|
8279
|
+
aF as PREVIEW_PLACEHOLDERS,
|
|
8280
|
+
aG as PRIMITIVE_MODE,
|
|
8281
|
+
aH as PRODUCT_LABEL_PREFIX,
|
|
7902
8282
|
PROSE_KEYS,
|
|
7903
8283
|
PROTECTION_PARTS,
|
|
7904
8284
|
PROTECTION_PART_PHRASE,
|
|
7905
8285
|
PUBLISH_LABEL,
|
|
7906
8286
|
PUBLISH_ROUTE_COPY,
|
|
7907
|
-
|
|
7908
|
-
|
|
8287
|
+
b42 as PULL_STATE_PILL,
|
|
8288
|
+
b52 as ProtectedBranchError,
|
|
7909
8289
|
RADIUS_PRESETS,
|
|
7910
|
-
|
|
8290
|
+
b62 as REDUCED_MOTION_NOTE,
|
|
7911
8291
|
REPO_MODEL_DEFAULTS,
|
|
7912
8292
|
REQUESTS_BRANCH,
|
|
7913
8293
|
REQUEST_KINDS,
|
|
7914
8294
|
REQUEST_LABEL,
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7919
|
-
|
|
8295
|
+
b72 as REQUEST_STATUS_LABEL,
|
|
8296
|
+
b82 as REVIEW_STATUS_LABEL,
|
|
8297
|
+
b92 as REVIEW_STATUS_ORDER,
|
|
8298
|
+
aI as RIGHTS,
|
|
8299
|
+
aJ as RIGHT_LABEL,
|
|
7920
8300
|
RISK_LABELS,
|
|
7921
|
-
|
|
8301
|
+
aK as RISK_TIER,
|
|
7922
8302
|
SHARE_EXPLAIN,
|
|
7923
8303
|
SIMILARITY_THRESHOLD,
|
|
7924
8304
|
SINGLE_MODE,
|
|
@@ -7933,38 +8313,38 @@ export {
|
|
|
7933
8313
|
SOURCE_FIGMA_LABEL,
|
|
7934
8314
|
SPEC_FIELDS,
|
|
7935
8315
|
STEPS,
|
|
7936
|
-
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
|
|
7940
|
-
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
8316
|
+
ba2 as SUGGESTION_APPLIED_MARK,
|
|
8317
|
+
bb2 as SUGGESTION_APPLY_EXIT,
|
|
8318
|
+
bc2 as SUGGESTION_FINAL_LABELS,
|
|
8319
|
+
bd2 as SUGGESTION_KINDS,
|
|
8320
|
+
be2 as SUGGESTION_LABEL,
|
|
8321
|
+
bf2 as SUGGESTION_LIMITS,
|
|
8322
|
+
bg2 as SUGGESTION_OVERRIDE_MARK,
|
|
8323
|
+
bh2 as SUGGESTION_REVIEW_MARK,
|
|
7944
8324
|
SUGGESTION_SCHEMA,
|
|
7945
|
-
|
|
7946
|
-
|
|
7947
|
-
|
|
7948
|
-
|
|
8325
|
+
bi2 as SUGGESTION_STATE_LABELS,
|
|
8326
|
+
bj2 as SUGGESTION_STATUS_LABEL,
|
|
8327
|
+
bk2 as SUGGESTION_STATUS_LABELS,
|
|
8328
|
+
bl2 as SUGGESTION_TOO_LARGE,
|
|
7949
8329
|
SnapshotError,
|
|
7950
|
-
|
|
7951
|
-
|
|
7952
|
-
|
|
8330
|
+
bm2 as StorybookIndexError,
|
|
8331
|
+
bn2 as SuggestionError,
|
|
8332
|
+
aL as TEAM_NAME_MAX,
|
|
7953
8333
|
TIER1_PUBLISH_HEADING,
|
|
7954
8334
|
TIER_AXIS,
|
|
7955
8335
|
TIER_NAMES,
|
|
7956
|
-
|
|
7957
|
-
|
|
7958
|
-
|
|
7959
|
-
|
|
7960
|
-
|
|
7961
|
-
|
|
7962
|
-
|
|
7963
|
-
|
|
7964
|
-
|
|
8336
|
+
aM as TIER_ORDER,
|
|
8337
|
+
bo2 as TOKEN_REJECTED_MESSAGE,
|
|
8338
|
+
bp2 as TOKEN_SETTINGS_URL,
|
|
8339
|
+
bq2 as TRIGGER_LABELS,
|
|
8340
|
+
aN as TeamDirectory,
|
|
8341
|
+
br2 as UNRELEASED,
|
|
8342
|
+
aO as VISUAL_CHECKS_DOCS,
|
|
8343
|
+
aP as VISUAL_CHECK_LABEL,
|
|
8344
|
+
aQ as VISUAL_WORKFLOW_FILES,
|
|
7965
8345
|
WAITING_FOR_CLAUDE_LABEL,
|
|
7966
|
-
|
|
7967
|
-
|
|
8346
|
+
bs2 as acceptDocsDraft,
|
|
8347
|
+
bt2 as acceptDocsText,
|
|
7968
8348
|
accessAtLeast,
|
|
7969
8349
|
accessState,
|
|
7970
8350
|
activityAge,
|
|
@@ -7975,47 +8355,50 @@ export {
|
|
|
7975
8355
|
activityRawUrl,
|
|
7976
8356
|
activityShaper,
|
|
7977
8357
|
activityTreeFilter,
|
|
8358
|
+
actorName,
|
|
7978
8359
|
addBrandToConfigText,
|
|
7979
8360
|
addedComment,
|
|
7980
|
-
|
|
7981
|
-
|
|
8361
|
+
aR as affectedContrast,
|
|
8362
|
+
aS as aliasOf,
|
|
7982
8363
|
aliasTarget,
|
|
7983
|
-
|
|
7984
|
-
|
|
8364
|
+
bu2 as allowedMergeMethods,
|
|
8365
|
+
bv2 as anatomyLabel,
|
|
7985
8366
|
anchoredRamp,
|
|
7986
8367
|
anthropicReplyText,
|
|
7987
8368
|
anthropicRequest,
|
|
7988
|
-
|
|
7989
|
-
|
|
8369
|
+
aT as appForProject,
|
|
8370
|
+
aU as appUrl,
|
|
7990
8371
|
appliedFixLines,
|
|
7991
|
-
|
|
8372
|
+
bw2 as appliedStatus,
|
|
7992
8373
|
applyConfirmedRenames,
|
|
7993
8374
|
applyDocsSections,
|
|
7994
8375
|
applyFixes,
|
|
7995
8376
|
applyTokenEdits,
|
|
7996
8377
|
applyTokenMerge,
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
|
|
8000
|
-
|
|
8378
|
+
bx2 as approvedSuggestionNumber,
|
|
8379
|
+
by2 as approvedSuggestionOnGitHub,
|
|
8380
|
+
aV as approverEntries,
|
|
8381
|
+
aW as approverLists,
|
|
8382
|
+
archiveExplorationOnGitHub,
|
|
8001
8383
|
askOthersToReviewOnGitHub,
|
|
8002
8384
|
assembleBuildRequests,
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
|
|
8385
|
+
bz2 as assertSafeBranch,
|
|
8386
|
+
bA2 as assignRequestOnGitHub,
|
|
8387
|
+
bB2 as assignVersions,
|
|
8006
8388
|
auditId,
|
|
8007
|
-
|
|
8389
|
+
bC2 as base64ToUtf8,
|
|
8008
8390
|
baseBranchOf,
|
|
8009
8391
|
bellChroma,
|
|
8010
8392
|
boundedCombos,
|
|
8011
|
-
|
|
8393
|
+
boxSized,
|
|
8394
|
+
aX as branchName,
|
|
8012
8395
|
branchPreviewUrls,
|
|
8013
|
-
|
|
8014
|
-
|
|
8396
|
+
aY as branchSlug,
|
|
8397
|
+
bD2 as branchVerdict,
|
|
8015
8398
|
branchWithJiraKey,
|
|
8016
8399
|
brandDisplayName,
|
|
8017
8400
|
brandPreviewVariables,
|
|
8018
|
-
|
|
8401
|
+
bE2 as bridgeMcpInstallCommand,
|
|
8019
8402
|
buildFidelityReport,
|
|
8020
8403
|
buildGapCase,
|
|
8021
8404
|
buildHistoryEntry,
|
|
@@ -8030,31 +8413,32 @@ export {
|
|
|
8030
8413
|
buildTokenSet,
|
|
8031
8414
|
buildUsageIndex,
|
|
8032
8415
|
canAddTo,
|
|
8033
|
-
|
|
8416
|
+
bF2 as canOverride,
|
|
8034
8417
|
canPublishTier1,
|
|
8035
8418
|
canShare,
|
|
8036
|
-
|
|
8037
|
-
|
|
8419
|
+
aZ as canShip,
|
|
8420
|
+
bG2 as canonicalJson,
|
|
8038
8421
|
capHistory,
|
|
8039
8422
|
changeEdits,
|
|
8040
|
-
|
|
8423
|
+
a_ as changeKind,
|
|
8041
8424
|
changeList,
|
|
8042
|
-
|
|
8043
|
-
|
|
8044
|
-
|
|
8045
|
-
|
|
8425
|
+
bH2 as changeTable,
|
|
8426
|
+
a$ as changedModes,
|
|
8427
|
+
changedThings,
|
|
8428
|
+
b0 as changesMode,
|
|
8429
|
+
bI2 as changesetBump,
|
|
8046
8430
|
checkBrandSlug,
|
|
8047
8431
|
checkLayeredPair,
|
|
8048
8432
|
choiceFor,
|
|
8049
|
-
|
|
8433
|
+
bJ2 as classifyAuth,
|
|
8050
8434
|
classifyLayered,
|
|
8051
8435
|
classifyRisk,
|
|
8052
|
-
|
|
8053
|
-
|
|
8436
|
+
bK2 as claudeStage,
|
|
8437
|
+
bL2 as cleanDocs,
|
|
8054
8438
|
cleanDocsText,
|
|
8055
8439
|
cleanDraftText,
|
|
8056
|
-
|
|
8057
|
-
|
|
8440
|
+
b1 as clearRawDeep,
|
|
8441
|
+
bM2 as clearSharedEtags,
|
|
8058
8442
|
closeExplorationOnGitHub,
|
|
8059
8443
|
closeOnGitHub,
|
|
8060
8444
|
closingIssueNumbers,
|
|
@@ -8064,138 +8448,148 @@ export {
|
|
|
8064
8448
|
collectRefs,
|
|
8065
8449
|
collectReleases,
|
|
8066
8450
|
colorDelta,
|
|
8067
|
-
|
|
8068
|
-
|
|
8451
|
+
b2 as colorToCss,
|
|
8452
|
+
b3 as colorsEqual,
|
|
8069
8453
|
combineChanges,
|
|
8070
8454
|
combineConflicts,
|
|
8071
|
-
|
|
8455
|
+
b4 as comboKey,
|
|
8072
8456
|
commentOnGitHub,
|
|
8073
|
-
|
|
8457
|
+
bN2 as commitFileOnGitHub,
|
|
8074
8458
|
commitLibraryResolution,
|
|
8075
|
-
|
|
8076
|
-
|
|
8459
|
+
b5 as commitMessage,
|
|
8460
|
+
b6 as compactJson,
|
|
8077
8461
|
compareImages,
|
|
8078
8462
|
compareSpecToMeasured,
|
|
8079
|
-
|
|
8463
|
+
bO2 as componentContrastPairs,
|
|
8080
8464
|
componentForPath,
|
|
8081
8465
|
componentMotion,
|
|
8082
8466
|
componentSlug,
|
|
8083
8467
|
componentSpecSuggestionPayload,
|
|
8084
8468
|
componentStatus,
|
|
8085
|
-
|
|
8469
|
+
bP2 as componentsUsingMotionToken,
|
|
8086
8470
|
composeBuildRequestIssue,
|
|
8087
|
-
|
|
8471
|
+
bQ2 as composeChangeset,
|
|
8088
8472
|
composeFiles,
|
|
8089
8473
|
composeNewBrandBody,
|
|
8090
8474
|
composePendingDrafts,
|
|
8091
|
-
|
|
8475
|
+
b7 as composePrBody,
|
|
8092
8476
|
composeProposalBody,
|
|
8093
8477
|
composeRequestIssue,
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
|
|
8478
|
+
bR2 as composeSuggestionAppliedComment,
|
|
8479
|
+
bS2 as composeSuggestionIssue,
|
|
8480
|
+
bT2 as composeSuggestionOverrideComment,
|
|
8481
|
+
bU2 as composeSuggestionReviewComment,
|
|
8482
|
+
b8 as composite,
|
|
8099
8483
|
conflictRoute,
|
|
8100
|
-
|
|
8484
|
+
b9 as contextFor,
|
|
8101
8485
|
contextLabel,
|
|
8102
|
-
|
|
8486
|
+
bV2 as continueDocsProposalOnGitHub,
|
|
8487
|
+
continueLines,
|
|
8488
|
+
continueRef,
|
|
8103
8489
|
contrastDelta,
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8490
|
+
bW2 as contrastDeltaTable,
|
|
8491
|
+
ba as contrastLevel,
|
|
8492
|
+
bb as contrastPair,
|
|
8493
|
+
bc as contrastRatio,
|
|
8108
8494
|
contrastScope,
|
|
8109
|
-
|
|
8110
|
-
|
|
8495
|
+
bX2 as countChanges,
|
|
8496
|
+
bY2 as coverageSummary,
|
|
8111
8497
|
createBuildRequestOnGitHub,
|
|
8112
8498
|
createDocsDraftSession,
|
|
8113
8499
|
createPendingDrafts,
|
|
8114
8500
|
createSuggestionOnGitHub,
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8501
|
+
bZ2 as cssColorToRgb,
|
|
8502
|
+
b_2 as cssColorsToRgb,
|
|
8503
|
+
b$2 as cssModuleClasses,
|
|
8118
8504
|
cssOf,
|
|
8119
8505
|
cssVarOf,
|
|
8120
8506
|
cssVarsIn,
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8507
|
+
c02 as declineComment,
|
|
8508
|
+
c12 as declineReasonProblems,
|
|
8509
|
+
c22 as declineRequestOnGitHub,
|
|
8510
|
+
c32 as declineSuggestionOnGitHub,
|
|
8125
8511
|
decodePicks,
|
|
8126
8512
|
defaultChoiceFor,
|
|
8127
|
-
|
|
8128
|
-
|
|
8513
|
+
bd as defaultContext,
|
|
8514
|
+
c42 as defaultDocsFooter,
|
|
8129
8515
|
defaultFile,
|
|
8130
8516
|
defaultModelConfig,
|
|
8131
8517
|
defaultProduct,
|
|
8132
8518
|
defaultScopes,
|
|
8133
|
-
|
|
8519
|
+
be as defaultTitle,
|
|
8134
8520
|
defineConfig,
|
|
8135
8521
|
deletePendingDrafts,
|
|
8136
8522
|
demoHistory,
|
|
8137
8523
|
describeDiff,
|
|
8138
8524
|
describePartFix,
|
|
8139
|
-
|
|
8525
|
+
bf as detectLayout,
|
|
8140
8526
|
diffLayered,
|
|
8141
8527
|
dismissStaleFrom,
|
|
8142
|
-
|
|
8143
|
-
|
|
8528
|
+
c52 as docsAuthorLine,
|
|
8529
|
+
c62 as docsFileText,
|
|
8144
8530
|
docsPrompt,
|
|
8145
|
-
|
|
8146
|
-
|
|
8531
|
+
c72 as docsProposal,
|
|
8532
|
+
c82 as docsSectionShapes,
|
|
8147
8533
|
docsSectionsAnswer,
|
|
8148
8534
|
docsSectionsResult,
|
|
8149
8535
|
docsSelectionPrompt,
|
|
8150
|
-
|
|
8151
|
-
|
|
8536
|
+
c92 as docsSlug,
|
|
8537
|
+
ca2 as docsSuggestionPayload,
|
|
8152
8538
|
docsTaskKeys,
|
|
8153
8539
|
docsTaskPrompt,
|
|
8154
|
-
|
|
8155
|
-
|
|
8540
|
+
cb2 as docsText,
|
|
8541
|
+
doneExploringOnGitHub,
|
|
8542
|
+
doneExploringPlan,
|
|
8543
|
+
cc2 as draftChangeLine,
|
|
8156
8544
|
draftImagePath,
|
|
8157
8545
|
draftItemBrief,
|
|
8158
|
-
|
|
8159
|
-
|
|
8546
|
+
cd2 as draftPushDescription,
|
|
8547
|
+
ce2 as draftRequestText,
|
|
8160
8548
|
draftSessionPath,
|
|
8161
8549
|
dtcgColor,
|
|
8162
8550
|
durationValue,
|
|
8163
8551
|
easingValue,
|
|
8164
8552
|
effectiveScopes,
|
|
8165
8553
|
effectiveTier,
|
|
8166
|
-
|
|
8554
|
+
cf2 as eligibleReviewers,
|
|
8167
8555
|
emptyTokenFile,
|
|
8168
8556
|
encodePicks,
|
|
8169
8557
|
ensureRequestsBranch,
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8558
|
+
bg as entriesFor,
|
|
8559
|
+
bh as entryLabel,
|
|
8560
|
+
cg2 as evalCalc,
|
|
8173
8561
|
evaluateContrastPairs,
|
|
8174
8562
|
evaluatePairs,
|
|
8175
|
-
|
|
8176
|
-
|
|
8177
|
-
|
|
8563
|
+
bi as expandEntries,
|
|
8564
|
+
bj as expandOwners,
|
|
8565
|
+
explorationActivity,
|
|
8566
|
+
ch2 as explorationBranch,
|
|
8178
8567
|
explorationNote,
|
|
8179
8568
|
explorationNotePath,
|
|
8180
8569
|
explorationPrBody,
|
|
8181
8570
|
explorationPrTitle,
|
|
8182
8571
|
explorationProblems,
|
|
8183
|
-
|
|
8184
|
-
|
|
8572
|
+
explorationRefLabel,
|
|
8573
|
+
ci2 as explorationRules,
|
|
8574
|
+
cj2 as explorationShareMessage,
|
|
8185
8575
|
explorationSlug,
|
|
8186
|
-
|
|
8576
|
+
ck2 as explorationSlugFromBranch,
|
|
8577
|
+
explorationStage,
|
|
8578
|
+
explorationStartMessage,
|
|
8579
|
+
explorationStartingPoint,
|
|
8187
8580
|
explorationStatus,
|
|
8188
8581
|
explorationSummary,
|
|
8582
|
+
cl2 as explorationTakeCommands,
|
|
8189
8583
|
explorationTestBuildOnGitHub,
|
|
8190
8584
|
explorationTryIt,
|
|
8191
8585
|
explorationTryItOnGitHub,
|
|
8192
|
-
|
|
8586
|
+
cm2 as fetchStorybookIndex,
|
|
8193
8587
|
fidelityComponentLine,
|
|
8194
8588
|
fidelityVerdict,
|
|
8195
|
-
|
|
8589
|
+
bk as fieldChanges,
|
|
8196
8590
|
figmaAheadLine,
|
|
8197
8591
|
figmaBranchTitle,
|
|
8198
|
-
|
|
8592
|
+
cn2 as figmaCell,
|
|
8199
8593
|
figmaChangeOnGitHub,
|
|
8200
8594
|
figmaDraftBody,
|
|
8201
8595
|
figmaDraftBrief,
|
|
@@ -8206,149 +8600,162 @@ export {
|
|
|
8206
8600
|
figmaNodeUrl,
|
|
8207
8601
|
figmaNodes,
|
|
8208
8602
|
figmaOriginSection,
|
|
8209
|
-
|
|
8603
|
+
bl as figmaPushNextLine,
|
|
8210
8604
|
figmaPushOf,
|
|
8211
8605
|
figmaPushScope,
|
|
8212
8606
|
figmaPushStatus,
|
|
8213
8607
|
figmaPushStatusesOnGitHub,
|
|
8214
|
-
|
|
8608
|
+
bm as figmaPushTierLabel,
|
|
8215
8609
|
figmaShipReviewBody,
|
|
8216
8610
|
figmaSpecPath,
|
|
8217
8611
|
figmaSpecSlug,
|
|
8218
|
-
|
|
8219
|
-
|
|
8612
|
+
co2 as fileModes,
|
|
8613
|
+
cp2 as filterHistory,
|
|
8220
8614
|
findExplorationOnGitHub,
|
|
8221
8615
|
findMeasure,
|
|
8222
|
-
|
|
8223
|
-
|
|
8616
|
+
cq2 as findOpenDocsProposal,
|
|
8617
|
+
cr2 as findOpenDocsProposalOnGitHub,
|
|
8224
8618
|
findPreviewComment,
|
|
8225
|
-
|
|
8619
|
+
bn as findProduct,
|
|
8226
8620
|
findReferenceProblems,
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8621
|
+
bo as findToken,
|
|
8622
|
+
bp as findVercelComment,
|
|
8623
|
+
cs2 as firstParagraph,
|
|
8230
8624
|
fitActivity,
|
|
8231
8625
|
fixLoopOutcome,
|
|
8232
8626
|
fixLoopRound,
|
|
8233
8627
|
fixPrompt,
|
|
8234
8628
|
fixWords,
|
|
8235
|
-
|
|
8629
|
+
bq as flattenLayerFile,
|
|
8236
8630
|
flattenTokenFile,
|
|
8237
8631
|
flattenTokens,
|
|
8238
8632
|
formatChangeset,
|
|
8239
|
-
|
|
8633
|
+
ct2 as formatDocsJson,
|
|
8240
8634
|
formatFigmaSpec,
|
|
8241
|
-
|
|
8242
|
-
|
|
8635
|
+
br as formatNumber,
|
|
8636
|
+
bs as formatOwnerEntry,
|
|
8243
8637
|
formatValue,
|
|
8244
8638
|
freshness,
|
|
8245
|
-
|
|
8639
|
+
cu2 as friendlyMessage,
|
|
8246
8640
|
fromHex,
|
|
8247
|
-
|
|
8641
|
+
bt as fromPlain,
|
|
8248
8642
|
gapCaseFor,
|
|
8249
8643
|
generateRamp,
|
|
8250
|
-
|
|
8251
|
-
|
|
8644
|
+
bu as getChild,
|
|
8645
|
+
bv as getEntry,
|
|
8252
8646
|
getSuggestionOnGitHub,
|
|
8253
8647
|
gitBlobSha,
|
|
8254
8648
|
gitHubHistoryBackend,
|
|
8255
8649
|
gitHubSource,
|
|
8256
|
-
|
|
8650
|
+
cv2 as githubSuggestionWorkspace,
|
|
8257
8651
|
globBase,
|
|
8258
8652
|
globToRegExp,
|
|
8259
8653
|
groupReleases,
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
|
|
8263
|
-
|
|
8264
|
-
|
|
8265
|
-
|
|
8654
|
+
cw2 as groupStorybookComponents,
|
|
8655
|
+
bw as groupsPhrase,
|
|
8656
|
+
cx2 as hasOwnerApproval,
|
|
8657
|
+
cy2 as hasSuggestionBlock,
|
|
8658
|
+
bx as hasVisualWorkflow,
|
|
8659
|
+
cz2 as hasWriteAccess,
|
|
8266
8660
|
hashSpec,
|
|
8267
8661
|
hexContrastRatio,
|
|
8268
8662
|
hexLuminance,
|
|
8269
|
-
|
|
8270
|
-
|
|
8271
|
-
|
|
8663
|
+
by as hexToRgba,
|
|
8664
|
+
bz as holdersOf,
|
|
8665
|
+
humanAuthorOf,
|
|
8666
|
+
cA2 as iconComponentName,
|
|
8272
8667
|
idExtensionFor,
|
|
8273
8668
|
impactedModules,
|
|
8274
8669
|
importsIn,
|
|
8275
|
-
|
|
8276
|
-
|
|
8277
|
-
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8670
|
+
inProductRepo,
|
|
8671
|
+
bA as indexByPath,
|
|
8672
|
+
bB as inheritedTypeAt,
|
|
8673
|
+
bC as installCommand,
|
|
8674
|
+
bD as installCommandFromPreviewComment,
|
|
8675
|
+
cB2 as installationFor,
|
|
8676
|
+
cC2 as isActiveExploration,
|
|
8281
8677
|
isAlias$1 as isAlias,
|
|
8282
|
-
|
|
8678
|
+
isArchivedExploration,
|
|
8679
|
+
cD2 as isAutomationPull,
|
|
8283
8680
|
isBuildRequestIssue,
|
|
8284
|
-
|
|
8681
|
+
isClaudeAssisted,
|
|
8682
|
+
isClaudeCommit,
|
|
8683
|
+
cE2 as isDocsProposalBranch,
|
|
8285
8684
|
isDocsSelectionMode,
|
|
8286
|
-
|
|
8685
|
+
cF2 as isDraft,
|
|
8287
8686
|
isDraftSessionId,
|
|
8288
8687
|
isExplorationBranch,
|
|
8289
8688
|
isExplorationPull,
|
|
8290
8689
|
isFigmaPush,
|
|
8291
8690
|
isGuardrail,
|
|
8292
|
-
|
|
8691
|
+
cG as isGuardrailPath,
|
|
8692
|
+
cH as isHandedOff,
|
|
8693
|
+
cI as isHeldExploration,
|
|
8293
8694
|
isHex,
|
|
8294
|
-
|
|
8295
|
-
|
|
8695
|
+
isHiddenRepoError,
|
|
8696
|
+
cJ as isJiraKey,
|
|
8697
|
+
cK as isMissingPermission,
|
|
8296
8698
|
isMultiMode,
|
|
8297
8699
|
isPlanRefusal,
|
|
8298
|
-
|
|
8700
|
+
cL as isPlatformRefusal,
|
|
8299
8701
|
isProseKey,
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8702
|
+
cM as isReleasePull,
|
|
8703
|
+
isStartCommit,
|
|
8704
|
+
bE as isTeamEntry,
|
|
8705
|
+
bF as isTokenFile,
|
|
8303
8706
|
isTokenPath,
|
|
8304
|
-
|
|
8707
|
+
cN as isTokenRejected,
|
|
8305
8708
|
isTokenValueChange,
|
|
8306
8709
|
isUnder,
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
|
|
8710
|
+
bG as isVercelComment,
|
|
8711
|
+
cO as jiraIssueFields,
|
|
8712
|
+
cP as jiraKeyOf,
|
|
8310
8713
|
jiraKeyOfLabels,
|
|
8311
|
-
|
|
8312
|
-
|
|
8714
|
+
cQ as joinRepoPath,
|
|
8715
|
+
bH as kindForMin,
|
|
8716
|
+
lastActivity,
|
|
8313
8717
|
layeredImpact,
|
|
8314
|
-
|
|
8718
|
+
bI as layeredParityIssues,
|
|
8315
8719
|
layoutOptions,
|
|
8316
8720
|
leadsPublishTier1On,
|
|
8317
8721
|
levenshtein,
|
|
8318
8722
|
libraryArrival,
|
|
8319
8723
|
libraryArrivalOnGitHub,
|
|
8320
8724
|
libraryBranchPlan,
|
|
8321
|
-
|
|
8725
|
+
bJ as libraryIsPublic,
|
|
8322
8726
|
libraryPreviewState,
|
|
8323
|
-
|
|
8727
|
+
cR as linkRequestToExplorationOnGitHub,
|
|
8324
8728
|
linkStatus,
|
|
8325
|
-
|
|
8729
|
+
cS as linkSuggestionPrOnGitHub,
|
|
8326
8730
|
linkedIssueNumbers,
|
|
8327
8731
|
linkedLibraryBranchOnGitHub,
|
|
8328
|
-
|
|
8732
|
+
cT as linkedPullsOf,
|
|
8329
8733
|
listBrands,
|
|
8330
8734
|
listBuildRequestsOnGitHub,
|
|
8331
8735
|
listExplorationsOnGitHub,
|
|
8332
8736
|
listFigmaChangesOnGitHub,
|
|
8333
8737
|
listPendingDrafts,
|
|
8738
|
+
listProductExplorationsOnGitHub,
|
|
8334
8739
|
listStylesheets,
|
|
8335
8740
|
listSuggestionsOnGitHub,
|
|
8741
|
+
listThings,
|
|
8336
8742
|
loadConfig,
|
|
8337
8743
|
loadGitHubHistory,
|
|
8338
8744
|
loadProtection,
|
|
8339
|
-
|
|
8745
|
+
cU as loadRepoFiles,
|
|
8340
8746
|
loadRepoModel,
|
|
8341
8747
|
loadRequiredChecks,
|
|
8342
8748
|
localTryCommand,
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8749
|
+
cV as lookAgainReviewers,
|
|
8750
|
+
cW as lowerFirstWord,
|
|
8751
|
+
bK as luminance,
|
|
8346
8752
|
mailtoHref,
|
|
8347
8753
|
mapPropsToFigma,
|
|
8348
8754
|
markClaudeDraft,
|
|
8349
8755
|
markFigmaChangeDraftedOnGitHub,
|
|
8350
|
-
|
|
8351
|
-
|
|
8756
|
+
cX as markSuggestionsAppliedOnGitHub,
|
|
8757
|
+
cY as markUsedTokens,
|
|
8758
|
+
matchVariant,
|
|
8352
8759
|
matchesBuildFilter,
|
|
8353
8760
|
mayBeTokenValueChange,
|
|
8354
8761
|
measureDir,
|
|
@@ -8357,158 +8764,169 @@ export {
|
|
|
8357
8764
|
measureWorkflowOptionsFromConfig,
|
|
8358
8765
|
measureWorkflowYaml,
|
|
8359
8766
|
measuredResolver,
|
|
8360
|
-
|
|
8361
|
-
|
|
8767
|
+
cZ as memoryEtagStore,
|
|
8768
|
+
c_ as memorySource,
|
|
8362
8769
|
mergeDocsDraft,
|
|
8363
8770
|
mergeDraftResults,
|
|
8364
8771
|
mergeFigmaFixes,
|
|
8365
|
-
|
|
8772
|
+
c$ as mergeGate,
|
|
8366
8773
|
mergeOnGitHub,
|
|
8367
8774
|
mergePiecesRecord,
|
|
8368
8775
|
mergeReleases,
|
|
8369
8776
|
missingChoices,
|
|
8370
|
-
|
|
8371
|
-
|
|
8777
|
+
d0 as missingPermissionMessage,
|
|
8778
|
+
d1 as missingProse,
|
|
8372
8779
|
modeDisplayName,
|
|
8373
8780
|
modeFile,
|
|
8374
|
-
|
|
8781
|
+
d2 as modeLabel,
|
|
8375
8782
|
modesOf$1 as modesOf,
|
|
8376
8783
|
motionDocs,
|
|
8377
8784
|
motionMoments,
|
|
8378
8785
|
moveToken,
|
|
8379
|
-
|
|
8786
|
+
bL as nearestQuestion,
|
|
8380
8787
|
nearestStep,
|
|
8381
|
-
|
|
8382
|
-
|
|
8788
|
+
bM as neededBySection,
|
|
8789
|
+
d3 as needsDocsReview,
|
|
8383
8790
|
neutralChroma,
|
|
8384
8791
|
neutralOffset,
|
|
8385
8792
|
newBrandSection,
|
|
8386
8793
|
newDraftSessionId,
|
|
8387
8794
|
noOnlinePreview,
|
|
8388
|
-
|
|
8795
|
+
bN as nodesEqual,
|
|
8389
8796
|
normalizeRepoPath,
|
|
8390
|
-
|
|
8391
|
-
|
|
8797
|
+
bO as normalizeRights,
|
|
8798
|
+
d4 as normalizeStorybookUrl,
|
|
8392
8799
|
noteSentences,
|
|
8393
8800
|
oklch,
|
|
8394
8801
|
oklchToLinear,
|
|
8802
|
+
onlyNotes,
|
|
8395
8803
|
onlyTokens,
|
|
8396
8804
|
openBuildRequests,
|
|
8397
8805
|
openComponentPushOnGitHub,
|
|
8398
8806
|
openLibraryBranchOnGitHub,
|
|
8399
|
-
|
|
8807
|
+
d5 as openPulls,
|
|
8400
8808
|
overlap,
|
|
8401
8809
|
overrideComment,
|
|
8402
|
-
|
|
8403
|
-
|
|
8810
|
+
d6 as overrideHolders,
|
|
8811
|
+
bP as overrideKey,
|
|
8404
8812
|
overrideMergeOnGitHub,
|
|
8405
|
-
|
|
8406
|
-
|
|
8813
|
+
d7 as overrideReasonMin,
|
|
8814
|
+
d8 as overrideReasonProblem,
|
|
8407
8815
|
overrideRefusedComment,
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8816
|
+
d9 as overrideSuggestionOnGitHub,
|
|
8817
|
+
bQ as ownerEntryProblems,
|
|
8818
|
+
da as ownerOverridePolicy,
|
|
8411
8819
|
packageDir,
|
|
8412
8820
|
packageDirCandidates,
|
|
8413
|
-
|
|
8821
|
+
bR as pairKey,
|
|
8414
8822
|
pairParts,
|
|
8415
8823
|
parentDir,
|
|
8416
8824
|
parseActivity,
|
|
8417
|
-
|
|
8825
|
+
db as parseBoxShadow,
|
|
8418
8826
|
parseBuildRequestIssue,
|
|
8419
8827
|
parseBuildSpec,
|
|
8420
8828
|
parseChangelog,
|
|
8421
8829
|
parseChangelogSections,
|
|
8422
8830
|
parseChangeset,
|
|
8423
|
-
|
|
8831
|
+
dc as parseChangesetText,
|
|
8424
8832
|
parseColor,
|
|
8425
8833
|
parseComponentCss,
|
|
8426
8834
|
parseComponentFamilies,
|
|
8427
8835
|
parseComponentSpecs,
|
|
8428
8836
|
parseComponentStories,
|
|
8429
8837
|
parseComponentTsx,
|
|
8838
|
+
parseContinueLine,
|
|
8430
8839
|
parseContrastChecks,
|
|
8431
8840
|
parseContrastSpecs,
|
|
8432
|
-
|
|
8841
|
+
bS as parseDimension,
|
|
8433
8842
|
parseDocsReply,
|
|
8434
8843
|
parseDocsTaskAnswer,
|
|
8435
8844
|
parseExplorationBody,
|
|
8845
|
+
dd as parseExplorationRef,
|
|
8436
8846
|
parseFidelityRun,
|
|
8437
8847
|
parseFigmaFixes,
|
|
8438
8848
|
parseFigmaOrigin,
|
|
8439
8849
|
parseFigmaSpec,
|
|
8440
8850
|
parseFixReply,
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8851
|
+
de as parseJiraKey,
|
|
8852
|
+
bT as parseJson,
|
|
8853
|
+
df as parseMeasuredSpecsFile,
|
|
8444
8854
|
parseModelConfig,
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8855
|
+
bU as parseNeededBy,
|
|
8856
|
+
dg as parseOverrideComment,
|
|
8857
|
+
bV as parseOwnerEntry,
|
|
8448
8858
|
parsePendingDrafts,
|
|
8449
8859
|
parsePiecesRecord,
|
|
8450
|
-
|
|
8860
|
+
dh as parseRepo,
|
|
8451
8861
|
parseRequestIssue,
|
|
8452
8862
|
parseSnapshot,
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8459
|
-
|
|
8863
|
+
di as parseStorybookIndex,
|
|
8864
|
+
dj as parseStructureChange,
|
|
8865
|
+
dk as parseSuggestionAppliedComment,
|
|
8866
|
+
dl as parseSuggestionIssue,
|
|
8867
|
+
dm as parseSuggestionOverrideComment,
|
|
8868
|
+
dn as parseSuggestionReviewComment,
|
|
8869
|
+
dp as parseTier,
|
|
8460
8870
|
parseTokenFile,
|
|
8461
|
-
|
|
8871
|
+
bW as parseVercelComment,
|
|
8462
8872
|
partLabel,
|
|
8463
8873
|
partWords,
|
|
8464
|
-
|
|
8874
|
+
dq as patchDocsJson,
|
|
8465
8875
|
pathId,
|
|
8466
8876
|
pathSimilarity,
|
|
8467
|
-
|
|
8468
|
-
|
|
8877
|
+
dr as pendingApprovals,
|
|
8878
|
+
ds as permissionLabel,
|
|
8469
8879
|
pickedOption,
|
|
8470
8880
|
p as pieceId,
|
|
8471
|
-
|
|
8472
|
-
|
|
8881
|
+
pieceRequest,
|
|
8882
|
+
bX as pieceValueField,
|
|
8883
|
+
bY as piecesSection,
|
|
8884
|
+
bZ as plainEqual,
|
|
8473
8885
|
planComponentPush,
|
|
8474
8886
|
planNewBrand,
|
|
8475
8887
|
planReference,
|
|
8476
8888
|
planReferences,
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8889
|
+
dt as planRestore,
|
|
8890
|
+
du as planRevert,
|
|
8891
|
+
dv as planSuggestionApply,
|
|
8892
|
+
dw as planToJson,
|
|
8481
8893
|
planTokenMerge,
|
|
8482
8894
|
planTokenProposal,
|
|
8483
8895
|
planVariantMeasures,
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8896
|
+
dx as prNumberFromSubject,
|
|
8897
|
+
dy as prefillDocs,
|
|
8898
|
+
b_ as previewComment,
|
|
8487
8899
|
previewLinks,
|
|
8488
|
-
|
|
8900
|
+
b$ as previewLinksOf,
|
|
8489
8901
|
previewOverrides,
|
|
8490
|
-
|
|
8902
|
+
previewUrl,
|
|
8491
8903
|
previewsSettled,
|
|
8492
8904
|
productBranchRef,
|
|
8493
8905
|
productBranchSentence,
|
|
8494
8906
|
productBranchViewOnGitHub,
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8907
|
+
c0 as productForPlace,
|
|
8908
|
+
c1 as productLabel,
|
|
8909
|
+
c2 as productMarks,
|
|
8498
8910
|
productOfBranch,
|
|
8911
|
+
productOfRepo,
|
|
8499
8912
|
productPreview,
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8913
|
+
productPreviewOnGitHub,
|
|
8914
|
+
c3 as productProblems,
|
|
8915
|
+
productRepoAccess,
|
|
8916
|
+
c4 as productRepoOf,
|
|
8917
|
+
productRepos,
|
|
8918
|
+
c5 as productsOf,
|
|
8919
|
+
c6 as projectOfLabel,
|
|
8503
8920
|
promoteExplorationOnGitHub,
|
|
8504
8921
|
promotionPlan,
|
|
8505
8922
|
propertyWords,
|
|
8506
|
-
|
|
8923
|
+
dz as proposeDocsOnGitHub,
|
|
8924
|
+
proposePiecesOnGitHub,
|
|
8507
8925
|
a as proposedTokenPath,
|
|
8508
|
-
|
|
8926
|
+
dA as propsTable,
|
|
8509
8927
|
protectLibrary,
|
|
8510
8928
|
protectRefusal,
|
|
8511
|
-
|
|
8929
|
+
c7 as protectedBranchesOf,
|
|
8512
8930
|
protectionRuleset,
|
|
8513
8931
|
protectionRulesetName,
|
|
8514
8932
|
protectionSentence,
|
|
@@ -8516,8 +8934,8 @@ export {
|
|
|
8516
8934
|
publishSummary,
|
|
8517
8935
|
publishedWithoutReview,
|
|
8518
8936
|
pullState,
|
|
8519
|
-
|
|
8520
|
-
|
|
8937
|
+
dB as pushChangeRows,
|
|
8938
|
+
dC as rateLimitMessage,
|
|
8521
8939
|
readCombineBranch,
|
|
8522
8940
|
readLibraryConflicts,
|
|
8523
8941
|
readPendingDrafts,
|
|
@@ -8533,24 +8951,24 @@ export {
|
|
|
8533
8951
|
referenceImagePath,
|
|
8534
8952
|
releaseAnnouncement,
|
|
8535
8953
|
releasePackagesLabel,
|
|
8536
|
-
|
|
8954
|
+
dD as releasePull,
|
|
8537
8955
|
releasesFromTags,
|
|
8538
8956
|
remoteRenames,
|
|
8539
8957
|
removeToken,
|
|
8540
8958
|
removedSide,
|
|
8541
|
-
|
|
8542
|
-
|
|
8959
|
+
c8 as renderedColor,
|
|
8960
|
+
dE as reopenEligibility,
|
|
8543
8961
|
reopenOnGitHub,
|
|
8544
|
-
|
|
8545
|
-
|
|
8962
|
+
dF as requestBrief,
|
|
8963
|
+
dG as requestImagePath,
|
|
8546
8964
|
requestIssueTitle,
|
|
8547
8965
|
requestStatus,
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8966
|
+
dH as requesterFirstName,
|
|
8967
|
+
dI as requesterLine,
|
|
8968
|
+
dJ as requesterOf,
|
|
8969
|
+
dK as requiredApprovals,
|
|
8552
8970
|
requiredCheckNames,
|
|
8553
|
-
|
|
8971
|
+
dL as requiredPermission,
|
|
8554
8972
|
resolutionMessage,
|
|
8555
8973
|
resolve,
|
|
8556
8974
|
resolveBranchPreviews,
|
|
@@ -8558,21 +8976,21 @@ export {
|
|
|
8558
8976
|
resolveRepoAccess,
|
|
8559
8977
|
resolvedTokenFiles,
|
|
8560
8978
|
reviewOnGitHub,
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
|
|
8979
|
+
dM as reviewQueue,
|
|
8980
|
+
dN as reviewStatusKind,
|
|
8981
|
+
dO as reviewStatusLabel,
|
|
8982
|
+
dP as reviewSuggestionOnGitHub,
|
|
8983
|
+
dQ as reviewersToAsk,
|
|
8984
|
+
c9 as rgbaToDtcg,
|
|
8567
8985
|
rgbaToHex,
|
|
8568
|
-
|
|
8986
|
+
ca as rightsProblems,
|
|
8569
8987
|
round3,
|
|
8570
8988
|
rulesSettingsUrl,
|
|
8571
8989
|
rulesetTargetsDefault,
|
|
8572
8990
|
runLayeredContrast,
|
|
8573
|
-
|
|
8991
|
+
cb as sameProducts,
|
|
8574
8992
|
sameScopes,
|
|
8575
|
-
|
|
8993
|
+
cc as sameToken,
|
|
8576
8994
|
sanitizeDocsReplacement,
|
|
8577
8995
|
sanitizeDocsResult,
|
|
8578
8996
|
sanitizeDocsSections,
|
|
@@ -8581,22 +8999,23 @@ export {
|
|
|
8581
8999
|
sanitizeDraftTitle,
|
|
8582
9000
|
sanitizeResultLines,
|
|
8583
9001
|
scanComponents,
|
|
8584
|
-
|
|
9002
|
+
dR as sectionsNeedingReview,
|
|
8585
9003
|
selectTokenFiles,
|
|
8586
|
-
|
|
9004
|
+
cd as serializeJson,
|
|
8587
9005
|
serializePendingDrafts,
|
|
8588
9006
|
serializeTokenFile,
|
|
8589
|
-
|
|
9007
|
+
dS as sha256Hex,
|
|
8590
9008
|
shadowedEdits,
|
|
8591
9009
|
shareDescription,
|
|
8592
9010
|
shareMessage,
|
|
8593
9011
|
shareState,
|
|
8594
|
-
|
|
8595
|
-
|
|
9012
|
+
dT as sharedTokenPrefix,
|
|
9013
|
+
ce as shipPolicy,
|
|
8596
9014
|
shipsByItself,
|
|
9015
|
+
shortAgo,
|
|
8597
9016
|
shortPackage,
|
|
8598
|
-
|
|
8599
|
-
|
|
9017
|
+
dU as shortVariant,
|
|
9018
|
+
dV as shortVariants,
|
|
8600
9019
|
showShare,
|
|
8601
9020
|
siteRepoFromConfig,
|
|
8602
9021
|
sizeGap,
|
|
@@ -8607,68 +9026,71 @@ export {
|
|
|
8607
9026
|
snapshotMotion,
|
|
8608
9027
|
snapshotSource,
|
|
8609
9028
|
snapshotSummary,
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
|
|
9029
|
+
cf as snapshotUrl,
|
|
9030
|
+
cg as soloApprover,
|
|
9031
|
+
ch as soloOwnerOf,
|
|
9032
|
+
ci as soloOwnerSentence,
|
|
8614
9033
|
sortChangelogEntries,
|
|
8615
|
-
|
|
9034
|
+
dW as specHash,
|
|
8616
9035
|
specsFromMeasure,
|
|
8617
|
-
|
|
9036
|
+
dX as specsUsage,
|
|
8618
9037
|
splitNote,
|
|
8619
9038
|
stableCommand,
|
|
8620
|
-
|
|
9039
|
+
dY as stalenessStatus,
|
|
8621
9040
|
startExplorationOnGitHub,
|
|
8622
9041
|
startFixLoop,
|
|
9042
|
+
startedWhen,
|
|
8623
9043
|
stateSentence,
|
|
8624
9044
|
statusFixFor,
|
|
8625
9045
|
storiesOfComponent,
|
|
8626
9046
|
storyForVariant,
|
|
8627
9047
|
storyMatchesWhere,
|
|
8628
9048
|
storyState,
|
|
8629
|
-
|
|
8630
|
-
|
|
8631
|
-
|
|
8632
|
-
|
|
9049
|
+
dZ as storybookIframeUrl,
|
|
9050
|
+
d_ as storybookIndexUrls,
|
|
9051
|
+
d$ as storybookManagerUrl,
|
|
9052
|
+
cj as storybookUrl,
|
|
8633
9053
|
styleGlobs,
|
|
8634
|
-
|
|
8635
|
-
|
|
9054
|
+
e0 as subjectTitle,
|
|
9055
|
+
subjectWords,
|
|
9056
|
+
ck as suggestNearestComment,
|
|
8636
9057
|
suggestTokenProposalOnGitHub,
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
|
|
8647
|
-
|
|
8648
|
-
|
|
8649
|
-
|
|
8650
|
-
|
|
8651
|
-
|
|
9058
|
+
e1 as suggestionAllowedRoots,
|
|
9059
|
+
e2 as suggestionAppliedComment,
|
|
9060
|
+
e3 as suggestionApplyTable,
|
|
9061
|
+
e4 as suggestionIsTokenValues,
|
|
9062
|
+
e5 as suggestionIssueTitle,
|
|
9063
|
+
e6 as suggestionKindFromLabels,
|
|
9064
|
+
e7 as suggestionLabelChanges,
|
|
9065
|
+
e8 as suggestionLabels,
|
|
9066
|
+
e9 as suggestionOverrideOf,
|
|
9067
|
+
ea as suggestionOverrideProblem,
|
|
9068
|
+
eb as suggestionPathProblems,
|
|
9069
|
+
ec as suggestionPayloadSha,
|
|
9070
|
+
ed as suggestionReviewState,
|
|
9071
|
+
ee as suggestionShapeProblems,
|
|
9072
|
+
ef as suggestionStalenessOnGitHub,
|
|
8652
9073
|
suggestionStateFromLabels,
|
|
8653
|
-
|
|
9074
|
+
eg as suggestionStateLabel,
|
|
8654
9075
|
suggestionStatus,
|
|
8655
|
-
|
|
8656
|
-
|
|
9076
|
+
eh as suggestionSubject,
|
|
9077
|
+
ei as suggestionTouches,
|
|
8657
9078
|
summarizeApprovals,
|
|
8658
9079
|
summarizeCi,
|
|
8659
9080
|
summarizeComponent,
|
|
8660
|
-
|
|
8661
|
-
|
|
9081
|
+
ej as summarizeSuggestionApprovals,
|
|
9082
|
+
cl as summarizeTokenChange,
|
|
8662
9083
|
switchToPublishedOnGitHub,
|
|
8663
|
-
|
|
9084
|
+
ek as syncSuggestionStateLabel,
|
|
8664
9085
|
takeMine,
|
|
8665
|
-
|
|
8666
|
-
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
9086
|
+
cm as tarballAssetName,
|
|
9087
|
+
cn as tarballUrl,
|
|
9088
|
+
co as teamKey,
|
|
9089
|
+
cp as teamKeyOf,
|
|
9090
|
+
cq as teamName,
|
|
9091
|
+
cr as teamUnreadableMessage,
|
|
9092
|
+
cs as teamsIn,
|
|
9093
|
+
thingOf,
|
|
8672
9094
|
threeWayDiff,
|
|
8673
9095
|
tier1Domain,
|
|
8674
9096
|
tier1PublishOf,
|
|
@@ -8676,23 +9098,23 @@ export {
|
|
|
8676
9098
|
tier1PublishSentence,
|
|
8677
9099
|
tier1PublishedBy,
|
|
8678
9100
|
tintedNeutral,
|
|
8679
|
-
|
|
9101
|
+
el as titleOf,
|
|
8680
9102
|
titleWithJiraKey,
|
|
8681
|
-
|
|
8682
|
-
|
|
9103
|
+
ct as toAlias,
|
|
9104
|
+
em as toChangeSummary,
|
|
8683
9105
|
toConfigJson,
|
|
8684
9106
|
toHex,
|
|
8685
|
-
|
|
9107
|
+
cu as toMap,
|
|
8686
9108
|
toOklch,
|
|
8687
|
-
|
|
8688
|
-
|
|
8689
|
-
|
|
9109
|
+
cv as toPlain,
|
|
9110
|
+
cw as tokenBump,
|
|
9111
|
+
en as tokenCssVar,
|
|
8690
9112
|
tokenFileChanges,
|
|
8691
9113
|
tokenFilesOf,
|
|
8692
|
-
|
|
8693
|
-
|
|
9114
|
+
eo as tokenFingerprint,
|
|
9115
|
+
ep as tokenHistory,
|
|
8694
9116
|
t as tokenLabel,
|
|
8695
|
-
|
|
9117
|
+
cx as tokenNode,
|
|
8696
9118
|
tokenPublishRoute,
|
|
8697
9119
|
tokenRepoFromMeasure,
|
|
8698
9120
|
tokenRowAxes,
|
|
@@ -8703,7 +9125,7 @@ export {
|
|
|
8703
9125
|
tokenSuggestionPayload,
|
|
8704
9126
|
tokenUsage,
|
|
8705
9127
|
tokenValueCss,
|
|
8706
|
-
|
|
9128
|
+
eq as tokenVariablePath,
|
|
8707
9129
|
tokensPath,
|
|
8708
9130
|
touchesLayout,
|
|
8709
9131
|
touchesPackages,
|
|
@@ -8712,50 +9134,53 @@ export {
|
|
|
8712
9134
|
tryInProductUrl,
|
|
8713
9135
|
tryTogetherUrl,
|
|
8714
9136
|
unpicked,
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
9137
|
+
cy as unreadableShipTeams,
|
|
9138
|
+
cz as unreadableTeams,
|
|
9139
|
+
er as unsafePathProblem,
|
|
8718
9140
|
updatePendingDrafts,
|
|
8719
9141
|
upsertToken,
|
|
8720
9142
|
useLibraryPreviewOnGitHub,
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
9143
|
+
es as utf8ToBase64,
|
|
9144
|
+
et as validateComponentSpec,
|
|
9145
|
+
eu as validateDocs,
|
|
8724
9146
|
validateDocsTask,
|
|
8725
9147
|
validateFigmaFixes,
|
|
8726
|
-
|
|
9148
|
+
ev as validateIntegrations,
|
|
8727
9149
|
validateLayered,
|
|
8728
9150
|
validatePendingDrafts,
|
|
8729
9151
|
validateProposal,
|
|
8730
9152
|
validateSet,
|
|
8731
|
-
|
|
8732
|
-
|
|
9153
|
+
cA as valueIn,
|
|
9154
|
+
cB as valueToCss,
|
|
8733
9155
|
valuesEqual,
|
|
8734
9156
|
variantCombosFromMapping,
|
|
8735
9157
|
variantDifferences,
|
|
8736
9158
|
variantKeyOf,
|
|
8737
|
-
|
|
9159
|
+
ew as variantName,
|
|
8738
9160
|
variantValuesFromMapping,
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
|
|
8742
|
-
|
|
8743
|
-
|
|
8744
|
-
|
|
8745
|
-
|
|
9161
|
+
ex as versionTimeline,
|
|
9162
|
+
cC as visualImpactProblems,
|
|
9163
|
+
cD as visualOffer,
|
|
9164
|
+
ey as webStorageEtagStore,
|
|
9165
|
+
whereItStands,
|
|
9166
|
+
cE as whoCanShipSentence,
|
|
9167
|
+
cF as whyItExists,
|
|
9168
|
+
ez as withAuthorLine,
|
|
9169
|
+
withDoneExploring,
|
|
8746
9170
|
withFigmaOrigin,
|
|
8747
|
-
|
|
9171
|
+
eA as withFigmaPushApprovals,
|
|
8748
9172
|
withLink,
|
|
8749
9173
|
withNeededBy,
|
|
8750
|
-
|
|
9174
|
+
eB as withOutdated,
|
|
8751
9175
|
withPiecesRecord,
|
|
8752
9176
|
withRepoTokenPaths,
|
|
8753
|
-
|
|
8754
|
-
|
|
8755
|
-
|
|
8756
|
-
|
|
9177
|
+
eC as withRequestExploration,
|
|
9178
|
+
eD as withSrgbColors,
|
|
9179
|
+
eE as withSuggestionApprovals,
|
|
9180
|
+
eF as withTokenValueApprovals,
|
|
8757
9181
|
withoutAddedWrappers,
|
|
8758
|
-
|
|
9182
|
+
eG as withoutJiraKey,
|
|
9183
|
+
wordsOf,
|
|
8759
9184
|
writeDraftResults,
|
|
8760
9185
|
writeTokenProposalOnGitHub
|
|
8761
9186
|
};
|