@bridge-ds/visual 0.3.5 → 0.3.7
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/index.js +83 -6
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -21,8 +21,8 @@ function parseOwnerEntry(raw) {
|
|
|
21
21
|
}
|
|
22
22
|
function ownerEntryProblems(raw) {
|
|
23
23
|
if (raw === void 0) return [];
|
|
24
|
-
const
|
|
25
|
-
if (!
|
|
24
|
+
const isObj3 = (x) => Boolean(x) && typeof x === "object" && !Array.isArray(x);
|
|
25
|
+
if (!isObj3(raw)) return ['"governance.owners" must be { "design": [people or teams], "tech": [people or teams] }'];
|
|
26
26
|
const out = [];
|
|
27
27
|
for (const [k, v] of Object.entries(raw)) {
|
|
28
28
|
if (k !== "design" && k !== "tech") {
|
|
@@ -256,7 +256,8 @@ function defineConfig(input) {
|
|
|
256
256
|
minReasonLength: g.override.minReasonLength ?? DEFAULT_OVERRIDE.minReasonLength
|
|
257
257
|
}
|
|
258
258
|
} : {},
|
|
259
|
-
...g.rights ? { rights: normalizeRights(g.rights) } : {}
|
|
259
|
+
...g.rights ? { rights: normalizeRights(g.rights) } : {},
|
|
260
|
+
...g.soloOwnerCanApproveBoth === true ? { soloOwnerCanApproveBoth: true } : {}
|
|
260
261
|
},
|
|
261
262
|
products: input.products?.length ? input.products.map((p) => ({ ...p })) : DEFAULT_PRODUCTS.map((p) => ({ ...p })),
|
|
262
263
|
changes: input.changes === "direct" ? "direct" : DEFAULT_CHANGES_MODE,
|
|
@@ -380,6 +381,7 @@ function loadConfig(source) {
|
|
|
380
381
|
}
|
|
381
382
|
}
|
|
382
383
|
problems.push(...rightsProblems(gov.rights));
|
|
384
|
+
if (gov.soloOwnerCanApproveBoth !== void 0 && typeof gov.soloOwnerCanApproveBoth !== "boolean") problems.push('"governance.soloOwnerCanApproveBoth" must be true or false');
|
|
383
385
|
}
|
|
384
386
|
}
|
|
385
387
|
problems.push(...visualImpactProblems(d.visualImpact));
|
|
@@ -989,6 +991,81 @@ function planReferences(file) {
|
|
|
989
991
|
);
|
|
990
992
|
}
|
|
991
993
|
|
|
994
|
+
// ../core/src/storybook.ts
|
|
995
|
+
var StorybookIndexError = class extends Error {
|
|
996
|
+
constructor(code, message, status) {
|
|
997
|
+
super(message);
|
|
998
|
+
this.code = code;
|
|
999
|
+
this.status = status;
|
|
1000
|
+
this.name = "StorybookIndexError";
|
|
1001
|
+
}
|
|
1002
|
+
code;
|
|
1003
|
+
status;
|
|
1004
|
+
};
|
|
1005
|
+
var isObj2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1006
|
+
var str = (v) => typeof v === "string" && v.trim() ? v : void 0;
|
|
1007
|
+
function entryFrom(key, raw, v3) {
|
|
1008
|
+
if (!isObj2(raw)) return null;
|
|
1009
|
+
const id = str(raw.id) ?? key;
|
|
1010
|
+
const title = str(raw.title) ?? str(raw.kind);
|
|
1011
|
+
const name = str(raw.name) ?? str(raw.story);
|
|
1012
|
+
if (!id || !title || !name) return null;
|
|
1013
|
+
const params = isObj2(raw.parameters) ? raw.parameters : {};
|
|
1014
|
+
const type = raw.type === "docs" || raw.type === "story" ? raw.type : v3 && params.docsOnly === true ? "docs" : "story";
|
|
1015
|
+
const e = {
|
|
1016
|
+
id,
|
|
1017
|
+
title,
|
|
1018
|
+
name,
|
|
1019
|
+
type,
|
|
1020
|
+
importPath: str(raw.importPath) ?? str(params.fileName) ?? "",
|
|
1021
|
+
tags: Array.isArray(raw.tags) ? raw.tags.filter((t) => typeof t === "string") : []
|
|
1022
|
+
};
|
|
1023
|
+
const subtype = str(raw.subtype);
|
|
1024
|
+
if (subtype) e.subtype = subtype;
|
|
1025
|
+
const exportName2 = str(raw.exportName);
|
|
1026
|
+
if (exportName2) e.exportName = exportName2;
|
|
1027
|
+
const componentPath = str(raw.componentPath);
|
|
1028
|
+
if (componentPath) e.componentPath = componentPath;
|
|
1029
|
+
return e;
|
|
1030
|
+
}
|
|
1031
|
+
function groupStorybookComponents(entries) {
|
|
1032
|
+
const byTitle = /* @__PURE__ */ new Map();
|
|
1033
|
+
for (const e of entries) {
|
|
1034
|
+
let c = byTitle.get(e.title);
|
|
1035
|
+
if (!c) {
|
|
1036
|
+
const parts = e.title.split("/").map((p) => p.trim()).filter(Boolean);
|
|
1037
|
+
c = { title: e.title, name: parts[parts.length - 1] ?? e.title, group: parts.slice(0, -1), stories: [], docs: [], tags: [] };
|
|
1038
|
+
byTitle.set(e.title, c);
|
|
1039
|
+
}
|
|
1040
|
+
if (e.type === "docs") c.docs.push(e);
|
|
1041
|
+
else if (e.subtype !== "test") c.stories.push(e);
|
|
1042
|
+
for (const t of e.tags) if (!c.tags.includes(t)) c.tags.push(t);
|
|
1043
|
+
}
|
|
1044
|
+
const out = [...byTitle.values()].filter((c) => c.stories.length || c.docs.length);
|
|
1045
|
+
for (const c of out) c.tags.sort();
|
|
1046
|
+
return out.sort((a, b) => a.title.localeCompare(b.title));
|
|
1047
|
+
}
|
|
1048
|
+
function parseStorybookIndex(json, source) {
|
|
1049
|
+
if (!isObj2(json)) throw new StorybookIndexError("not-json", "The Storybook index is not a JSON object.");
|
|
1050
|
+
if (typeof json.loginUrl === "string" && !("entries" in json) && !("stories" in json)) {
|
|
1051
|
+
throw new StorybookIndexError("private", "This Storybook is private: it asks for a sign-in before showing its index.");
|
|
1052
|
+
}
|
|
1053
|
+
const map = isObj2(json.entries) ? json.entries : isObj2(json.stories) ? json.stories : null;
|
|
1054
|
+
if (!map) throw new StorybookIndexError("empty", "This file has no Storybook entries.");
|
|
1055
|
+
const v3 = !isObj2(json.entries);
|
|
1056
|
+
const entries = Object.entries(map).map(([k, raw]) => entryFrom(k, raw, v3)).filter((e) => e !== null);
|
|
1057
|
+
if (!entries.length) throw new StorybookIndexError("empty", "This Storybook index lists no stories or docs.");
|
|
1058
|
+
const version = typeof json.v === "number" ? json.v : v3 ? 3 : 4;
|
|
1059
|
+
return { version, source: source ?? (v3 ? "stories.json" : "index.json"), entries, components: groupStorybookComponents(entries) };
|
|
1060
|
+
}
|
|
1061
|
+
var pairs = (o) => Object.entries(o).map(([k, v]) => `${encodeURIComponent(k)}:${encodeURIComponent(v)}`).join(";");
|
|
1062
|
+
function storybookIframeUrl(base, id, o = {}) {
|
|
1063
|
+
let url = `${base.replace(/\/+$/, "")}/iframe.html?id=${encodeURIComponent(id)}&viewMode=${o.viewMode ?? "story"}`;
|
|
1064
|
+
if (o.globals && Object.keys(o.globals).length) url += `&globals=${pairs(o.globals)}`;
|
|
1065
|
+
if (o.args && Object.keys(o.args).length) url += `&args=${pairs(o.args)}`;
|
|
1066
|
+
return url;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
992
1069
|
// ../core/src/node/git-local.ts
|
|
993
1070
|
import { execFile } from "node:child_process";
|
|
994
1071
|
function git(root, args, opts = {}) {
|
|
@@ -1405,7 +1482,7 @@ function routeUrl(base, route, tenant, theme) {
|
|
|
1405
1482
|
return `${base.replace(/\/$/, "")}/?tenant=${encodeURIComponent(tenant)}&theme=${encodeURIComponent(theme)}&density=comfortable&lang=en#${route.pathByTenant?.[tenant] ?? route.path}`;
|
|
1406
1483
|
}
|
|
1407
1484
|
function storyUrl(base, id, brand, theme) {
|
|
1408
|
-
return
|
|
1485
|
+
return storybookIframeUrl(base, id, { globals: { brand, theme, density: "comfortable" } });
|
|
1409
1486
|
}
|
|
1410
1487
|
var shotKey = (...parts) => parts.map((p) => p.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-|-$/g, "")).join("__");
|
|
1411
1488
|
|
|
@@ -1696,8 +1773,8 @@ function changedTokens(before, after) {
|
|
|
1696
1773
|
return [...modes.entries()].map(([path, m]) => ({ path, kind: direct.has(path) ? "direct" : "alias", modes: m })).sort((a, b) => Number(a.kind === "alias") - Number(b.kind === "alias") || a.path.localeCompare(b.path));
|
|
1697
1774
|
}
|
|
1698
1775
|
async function readIndexJson(dir) {
|
|
1699
|
-
const
|
|
1700
|
-
return
|
|
1776
|
+
const index = parseStorybookIndex(JSON.parse(await readFile3(join3(dir, "index.json"), "utf8")), "index.json");
|
|
1777
|
+
return index.entries.filter((e) => e.type === "story").map(({ id, title, name, importPath }) => ({ id, title, name, importPath }));
|
|
1701
1778
|
}
|
|
1702
1779
|
async function planImpact(o) {
|
|
1703
1780
|
const root = resolve(o.root);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bridge-ds/visual",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Bridge visual impact analysis: screenshots the stories and app screens a design system change touches, at the base and head refs, and pixel-diffs them into before/after/diff images and a JSON manifest.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"build:package": "node ../../scripts/build-packages.mjs visual"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@bridge-ds/core": "^0.
|
|
50
|
+
"@bridge-ds/core": "^0.13.0",
|
|
51
51
|
"pixelmatch": "7.1.0",
|
|
52
52
|
"playwright-core": "1.63.0",
|
|
53
53
|
"pngjs": "7.0.0"
|