happo 6.12.0 → 6.13.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.
Files changed (61) hide show
  1. package/dist/cli/cancelJob-X6WN6AHI.js +10 -0
  2. package/dist/cli/{chunk-NAZ3MMJW.js → chunk-DKTZGFEN.js} +3 -2
  3. package/dist/cli/chunk-DKTZGFEN.js.map +7 -0
  4. package/dist/cli/{chunk-6LZEMKE5.js → chunk-KHHTPRKU.js} +2 -2
  5. package/dist/cli/{chunk-SZM5DT7T.js → chunk-OGKEBLDS.js} +2 -2
  6. package/dist/cli/{chunk-KJAXUBWS.js → chunk-Q5QFRFFU.js} +2 -2
  7. package/dist/cli/{chunk-UE2TDVXX.js → chunk-WBVBJ4BH.js} +3 -3
  8. package/dist/cli/{chunk-TRVYVBOG.js → chunk-Z63LRWUL.js} +2 -2
  9. package/dist/cli/createAsyncComparison-2IFZGTYT.js +10 -0
  10. package/dist/cli/{createAsyncReport-6NLFV67D.js → createAsyncReport-KJOLZDLC.js} +4 -4
  11. package/dist/cli/{createExtendsReportSnapRequest-NLOQRLLD.js → createExtendsReportSnapRequest-IRHFVRCI.js} +4 -4
  12. package/dist/cli/{findBaselineReport-Z3OCRSBZ.js → findBaselineReport-3U3N2BB6.js} +4 -4
  13. package/dist/cli/{getFlakes-XLUPRYOV.js → getFlakes-36553LJ7.js} +4 -4
  14. package/dist/cli/main.js +15 -15
  15. package/dist/cli/package-BBL2QL2E.js +7 -0
  16. package/dist/cli/{prepareSnapRequests-LEKHRAYP.js → prepareSnapRequests-NIN2NCRF.js} +6 -6
  17. package/dist/cli/{prepareSnapRequests-LEKHRAYP.js.map → prepareSnapRequests-NIN2NCRF.js.map} +1 -1
  18. package/dist/cli/startJob-BPJRINPZ.js +10 -0
  19. package/dist/cli/{wrapper-RZ37F2SC.js → wrapper-WXSMHY3Z.js} +7 -7
  20. package/dist/cypress/task.js +28 -16
  21. package/dist/cypress/task.js.map +3 -3
  22. package/dist/e2e/controller.d.ts.map +1 -1
  23. package/dist/playwright/index.d.ts.map +1 -1
  24. package/dist/playwright/index.js +35 -17
  25. package/dist/playwright/index.js.map +3 -3
  26. package/dist/storybook/browser/addon-v8.d.ts +2 -0
  27. package/dist/storybook/browser/addon-v8.d.ts.map +1 -0
  28. package/dist/storybook/browser/addon-v8.js +95 -0
  29. package/dist/storybook/browser/addon-v8.js.map +7 -0
  30. package/dist/storybook/browser/addon.js.map +2 -2
  31. package/dist/storybook/browser/decorator.d.ts +1 -1
  32. package/dist/storybook/browser/decorator.d.ts.map +1 -1
  33. package/dist/storybook/browser/decorator.js +1 -1
  34. package/dist/storybook/browser/decorator.js.map +1 -1
  35. package/dist/storybook/chunk-YBRVICYB.js +89 -0
  36. package/dist/storybook/chunk-YBRVICYB.js.map +7 -0
  37. package/dist/storybook/index.js +20 -101
  38. package/dist/storybook/index.js.map +4 -4
  39. package/dist/storybook/preset.d.ts.map +1 -1
  40. package/dist/storybook/preset.js +7 -1
  41. package/dist/storybook/preset.js.map +2 -2
  42. package/package.json +2 -1
  43. package/dist/cli/cancelJob-3SOJDWVF.js +0 -10
  44. package/dist/cli/chunk-NAZ3MMJW.js.map +0 -7
  45. package/dist/cli/createAsyncComparison-Z4CFUYI3.js +0 -10
  46. package/dist/cli/package-KZLXYPVK.js +0 -7
  47. package/dist/cli/startJob-I4XOEWJR.js +0 -10
  48. /package/dist/cli/{cancelJob-3SOJDWVF.js.map → cancelJob-X6WN6AHI.js.map} +0 -0
  49. /package/dist/cli/{chunk-6LZEMKE5.js.map → chunk-KHHTPRKU.js.map} +0 -0
  50. /package/dist/cli/{chunk-SZM5DT7T.js.map → chunk-OGKEBLDS.js.map} +0 -0
  51. /package/dist/cli/{chunk-KJAXUBWS.js.map → chunk-Q5QFRFFU.js.map} +0 -0
  52. /package/dist/cli/{chunk-UE2TDVXX.js.map → chunk-WBVBJ4BH.js.map} +0 -0
  53. /package/dist/cli/{chunk-TRVYVBOG.js.map → chunk-Z63LRWUL.js.map} +0 -0
  54. /package/dist/cli/{createAsyncComparison-Z4CFUYI3.js.map → createAsyncComparison-2IFZGTYT.js.map} +0 -0
  55. /package/dist/cli/{createAsyncReport-6NLFV67D.js.map → createAsyncReport-KJOLZDLC.js.map} +0 -0
  56. /package/dist/cli/{createExtendsReportSnapRequest-NLOQRLLD.js.map → createExtendsReportSnapRequest-IRHFVRCI.js.map} +0 -0
  57. /package/dist/cli/{findBaselineReport-Z3OCRSBZ.js.map → findBaselineReport-3U3N2BB6.js.map} +0 -0
  58. /package/dist/cli/{getFlakes-XLUPRYOV.js.map → getFlakes-36553LJ7.js.map} +0 -0
  59. /package/dist/cli/{package-KZLXYPVK.js.map → package-BBL2QL2E.js.map} +0 -0
  60. /package/dist/cli/{startJob-I4XOEWJR.js.map → startJob-BPJRINPZ.js.map} +0 -0
  61. /package/dist/cli/{wrapper-RZ37F2SC.js.map → wrapper-WXSMHY3Z.js.map} +0 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=addon-v8.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addon-v8.d.ts","sourceRoot":"","sources":["../../../src/storybook/browser/addon-v8.ts"],"names":[],"mappings":""}
@@ -0,0 +1,95 @@
1
+ // src/storybook/browser/addon-v8.ts
2
+ import { createElement, useEffect, useState } from "react";
3
+ import { AddonPanel } from "storybook/internal/components";
4
+ import {
5
+ addons,
6
+ types,
7
+ useChannel,
8
+ useParameter,
9
+ useStorybookState
10
+ } from "storybook/internal/manager-api";
11
+ var ADDON_ID = "happo";
12
+ var PANEL_ID = `${ADDON_ID}/panel`;
13
+ function HappoPanel() {
14
+ const happoParams = useParameter("happo", null);
15
+ const state = useStorybookState();
16
+ const emit = useChannel({});
17
+ const [functionParams, setFunctionParams] = useState([]);
18
+ useEffect(() => {
19
+ function listen(event) {
20
+ setFunctionParams(event.params);
21
+ }
22
+ addons.getChannel().on("happo/functions/params", listen);
23
+ return () => {
24
+ addons.getChannel().off("happo/functions/params", listen);
25
+ };
26
+ }, [state.storyId]);
27
+ return createElement(
28
+ "div",
29
+ {
30
+ style: {
31
+ padding: 10,
32
+ fontSize: 12
33
+ }
34
+ },
35
+ happoParams ? createElement(
36
+ "table",
37
+ null,
38
+ createElement(
39
+ "tbody",
40
+ null,
41
+ Object.keys(happoParams).map((key) => {
42
+ const val = happoParams[key];
43
+ return createElement(
44
+ "tr",
45
+ { key },
46
+ createElement("td", null, createElement("code", null, `${key}:`)),
47
+ createElement(
48
+ "td",
49
+ null,
50
+ createElement("code", null, JSON.stringify(val))
51
+ )
52
+ );
53
+ }),
54
+ functionParams.map((param) => {
55
+ return createElement(
56
+ "tr",
57
+ { key: param.key },
58
+ createElement(
59
+ "td",
60
+ null,
61
+ createElement("code", null, `${param.key}:`)
62
+ ),
63
+ createElement(
64
+ "td",
65
+ null,
66
+ createElement(
67
+ "button",
68
+ {
69
+ onClick: () => emit("happo/functions/invoke", {
70
+ storyId: state.storyId,
71
+ funcName: param.key
72
+ })
73
+ },
74
+ "Invoke"
75
+ )
76
+ )
77
+ );
78
+ })
79
+ )
80
+ ) : createElement("div", null, "No happo params for this story")
81
+ );
82
+ }
83
+ addons.register(ADDON_ID, () => {
84
+ addons.add(PANEL_ID, {
85
+ type: types.PANEL,
86
+ title: "Happo",
87
+ render: ({ active }) => {
88
+ return createElement(AddonPanel, {
89
+ active: active ?? false,
90
+ children: createElement(HappoPanel, null)
91
+ });
92
+ }
93
+ });
94
+ });
95
+ //# sourceMappingURL=addon-v8.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/storybook/browser/addon-v8.ts"],
4
+ "sourcesContent": ["// NOTE: This file is intentionally duplicated as addon.ts. The two files\n// are identical except for the manager-api import path: Storybook v8 exposes\n// it at 'storybook/internal/manager-api' while v9+ use 'storybook/manager-api'.\n// No single path works across all three major versions (v8/v9/v10), and the\n// React hooks used here can't be cleanly injected to share an implementation,\n// so the duplication is kept explicit. Keep the two files in sync.\nimport { createElement, useEffect, useState } from 'react';\nimport { AddonPanel } from 'storybook/internal/components';\nimport {\n addons,\n types,\n useChannel,\n useParameter,\n useStorybookState,\n} from 'storybook/internal/manager-api';\n\nconst ADDON_ID = 'happo';\nconst PANEL_ID = `${ADDON_ID}/panel`;\n\ninterface FunctionParam {\n key: string;\n}\n\nfunction HappoPanel() {\n const happoParams = useParameter('happo', null);\n const state = useStorybookState();\n const emit = useChannel({});\n const [functionParams, setFunctionParams] = useState<Array<FunctionParam>>([]);\n\n useEffect(() => {\n function listen(event: { params: Array<FunctionParam> }) {\n setFunctionParams(event.params);\n }\n\n addons.getChannel().on('happo/functions/params', listen);\n\n return () => {\n addons.getChannel().off('happo/functions/params', listen);\n };\n }, [state.storyId]);\n\n return createElement(\n 'div',\n {\n style: {\n padding: 10,\n fontSize: 12,\n },\n },\n happoParams\n ? createElement(\n 'table',\n null,\n createElement(\n 'tbody',\n null,\n Object.keys(happoParams).map((key) => {\n const val = happoParams[key];\n\n return createElement(\n 'tr',\n { key: key },\n createElement('td', null, createElement('code', null, `${key}:`)),\n createElement(\n 'td',\n null,\n createElement('code', null, JSON.stringify(val)),\n ),\n );\n }),\n functionParams.map((param) => {\n return createElement(\n 'tr',\n { key: param.key },\n createElement(\n 'td',\n null,\n createElement('code', null, `${param.key}:`),\n ),\n createElement(\n 'td',\n null,\n createElement(\n 'button',\n {\n onClick: () =>\n emit('happo/functions/invoke', {\n storyId: state.storyId,\n funcName: param.key,\n }),\n },\n 'Invoke',\n ),\n ),\n );\n }),\n ),\n )\n : createElement('div', null, 'No happo params for this story'),\n );\n}\n\naddons.register(ADDON_ID, () => {\n addons.add(PANEL_ID, {\n type: types.PANEL,\n title: 'Happo',\n render: ({ active }) => {\n return createElement(AddonPanel, {\n active: active ?? false,\n children: createElement(HappoPanel, null),\n });\n },\n });\n});\n"],
5
+ "mappings": ";AAMA,SAAS,eAAe,WAAW,gBAAgB;AACnD,SAAS,kBAAkB;AAC3B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,IAAM,WAAW;AACjB,IAAM,WAAW,GAAG,QAAQ;AAM5B,SAAS,aAAa;AACpB,QAAM,cAAc,aAAa,SAAS,IAAI;AAC9C,QAAM,QAAQ,kBAAkB;AAChC,QAAM,OAAO,WAAW,CAAC,CAAC;AAC1B,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAA+B,CAAC,CAAC;AAE7E,YAAU,MAAM;AACd,aAAS,OAAO,OAAyC;AACvD,wBAAkB,MAAM,MAAM;AAAA,IAChC;AAEA,WAAO,WAAW,EAAE,GAAG,0BAA0B,MAAM;AAEvD,WAAO,MAAM;AACX,aAAO,WAAW,EAAE,IAAI,0BAA0B,MAAM;AAAA,IAC1D;AAAA,EACF,GAAG,CAAC,MAAM,OAAO,CAAC;AAElB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,QACL,SAAS;AAAA,QACT,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,IACA,cACI;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA,OAAO,KAAK,WAAW,EAAE,IAAI,CAAC,QAAQ;AACpC,gBAAM,MAAM,YAAY,GAAG;AAE3B,iBAAO;AAAA,YACL;AAAA,YACA,EAAE,IAAS;AAAA,YACX,cAAc,MAAM,MAAM,cAAc,QAAQ,MAAM,GAAG,GAAG,GAAG,CAAC;AAAA,YAChE;AAAA,cACE;AAAA,cACA;AAAA,cACA,cAAc,QAAQ,MAAM,KAAK,UAAU,GAAG,CAAC;AAAA,YACjD;AAAA,UACF;AAAA,QACF,CAAC;AAAA,QACD,eAAe,IAAI,CAAC,UAAU;AAC5B,iBAAO;AAAA,YACL;AAAA,YACA,EAAE,KAAK,MAAM,IAAI;AAAA,YACjB;AAAA,cACE;AAAA,cACA;AAAA,cACA,cAAc,QAAQ,MAAM,GAAG,MAAM,GAAG,GAAG;AAAA,YAC7C;AAAA,YACA;AAAA,cACE;AAAA,cACA;AAAA,cACA;AAAA,gBACE;AAAA,gBACA;AAAA,kBACE,SAAS,MACP,KAAK,0BAA0B;AAAA,oBAC7B,SAAS,MAAM;AAAA,oBACf,UAAU,MAAM;AAAA,kBAClB,CAAC;AAAA,gBACL;AAAA,gBACA;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,IACA,cAAc,OAAO,MAAM,gCAAgC;AAAA,EACjE;AACF;AAEA,OAAO,SAAS,UAAU,MAAM;AAC9B,SAAO,IAAI,UAAU;AAAA,IACnB,MAAM,MAAM;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ,CAAC,EAAE,OAAO,MAAM;AACtB,aAAO,cAAc,YAAY;AAAA,QAC/B,QAAQ,UAAU;AAAA,QAClB,UAAU,cAAc,YAAY,IAAI;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH,CAAC;",
6
+ "names": []
7
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/storybook/browser/addon.ts"],
4
- "sourcesContent": ["import { createElement, useEffect, useState } from 'react';\nimport { AddonPanel } from 'storybook/internal/components';\nimport {\n addons,\n types,\n useChannel,\n useParameter,\n useStorybookState,\n} from 'storybook/manager-api';\n\nconst ADDON_ID = 'happo';\nconst PANEL_ID = `${ADDON_ID}/panel`;\n\ninterface FunctionParam {\n key: string;\n}\n\nfunction HappoPanel() {\n const happoParams = useParameter('happo', null);\n const state = useStorybookState();\n const emit = useChannel({});\n const [functionParams, setFunctionParams] = useState<Array<FunctionParam>>([]);\n\n useEffect(() => {\n function listen(event: { params: Array<FunctionParam> }) {\n setFunctionParams(event.params);\n }\n\n addons.getChannel().on('happo/functions/params', listen);\n\n return () => {\n addons.getChannel().off('happo/functions/params', listen);\n };\n }, [state.storyId]);\n\n return createElement(\n 'div',\n {\n style: {\n padding: 10,\n fontSize: 12,\n },\n },\n happoParams\n ? createElement(\n 'table',\n null,\n createElement(\n 'tbody',\n null,\n Object.keys(happoParams).map((key) => {\n const val = happoParams[key];\n\n return createElement(\n 'tr',\n { key: key },\n createElement('td', null, createElement('code', null, `${key}:`)),\n createElement(\n 'td',\n null,\n createElement('code', null, JSON.stringify(val)),\n ),\n );\n }),\n functionParams.map((param) => {\n return createElement(\n 'tr',\n { key: param.key },\n createElement(\n 'td',\n null,\n createElement('code', null, `${param.key}:`),\n ),\n createElement(\n 'td',\n null,\n createElement(\n 'button',\n {\n onClick: () =>\n emit('happo/functions/invoke', {\n storyId: state.storyId,\n funcName: param.key,\n }),\n },\n 'Invoke',\n ),\n ),\n );\n }),\n ),\n )\n : createElement('div', null, 'No happo params for this story'),\n );\n}\n\naddons.register(ADDON_ID, () => {\n addons.add(PANEL_ID, {\n type: types.PANEL,\n title: 'Happo',\n render: ({ active }) => {\n return createElement(AddonPanel, {\n active: active ?? false,\n children: createElement(HappoPanel, null),\n });\n },\n });\n});\n"],
5
- "mappings": ";AAAA,SAAS,eAAe,WAAW,gBAAgB;AACnD,SAAS,kBAAkB;AAC3B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,IAAM,WAAW;AACjB,IAAM,WAAW,GAAG,QAAQ;AAM5B,SAAS,aAAa;AACpB,QAAM,cAAc,aAAa,SAAS,IAAI;AAC9C,QAAM,QAAQ,kBAAkB;AAChC,QAAM,OAAO,WAAW,CAAC,CAAC;AAC1B,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAA+B,CAAC,CAAC;AAE7E,YAAU,MAAM;AACd,aAAS,OAAO,OAAyC;AACvD,wBAAkB,MAAM,MAAM;AAAA,IAChC;AAEA,WAAO,WAAW,EAAE,GAAG,0BAA0B,MAAM;AAEvD,WAAO,MAAM;AACX,aAAO,WAAW,EAAE,IAAI,0BAA0B,MAAM;AAAA,IAC1D;AAAA,EACF,GAAG,CAAC,MAAM,OAAO,CAAC;AAElB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,QACL,SAAS;AAAA,QACT,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,IACA,cACI;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA,OAAO,KAAK,WAAW,EAAE,IAAI,CAAC,QAAQ;AACpC,gBAAM,MAAM,YAAY,GAAG;AAE3B,iBAAO;AAAA,YACL;AAAA,YACA,EAAE,IAAS;AAAA,YACX,cAAc,MAAM,MAAM,cAAc,QAAQ,MAAM,GAAG,GAAG,GAAG,CAAC;AAAA,YAChE;AAAA,cACE;AAAA,cACA;AAAA,cACA,cAAc,QAAQ,MAAM,KAAK,UAAU,GAAG,CAAC;AAAA,YACjD;AAAA,UACF;AAAA,QACF,CAAC;AAAA,QACD,eAAe,IAAI,CAAC,UAAU;AAC5B,iBAAO;AAAA,YACL;AAAA,YACA,EAAE,KAAK,MAAM,IAAI;AAAA,YACjB;AAAA,cACE;AAAA,cACA;AAAA,cACA,cAAc,QAAQ,MAAM,GAAG,MAAM,GAAG,GAAG;AAAA,YAC7C;AAAA,YACA;AAAA,cACE;AAAA,cACA;AAAA,cACA;AAAA,gBACE;AAAA,gBACA;AAAA,kBACE,SAAS,MACP,KAAK,0BAA0B;AAAA,oBAC7B,SAAS,MAAM;AAAA,oBACf,UAAU,MAAM;AAAA,kBAClB,CAAC;AAAA,gBACL;AAAA,gBACA;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,IACA,cAAc,OAAO,MAAM,gCAAgC;AAAA,EACjE;AACF;AAEA,OAAO,SAAS,UAAU,MAAM;AAC9B,SAAO,IAAI,UAAU;AAAA,IACnB,MAAM,MAAM;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ,CAAC,EAAE,OAAO,MAAM;AACtB,aAAO,cAAc,YAAY;AAAA,QAC/B,QAAQ,UAAU;AAAA,QAClB,UAAU,cAAc,YAAY,IAAI;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH,CAAC;",
4
+ "sourcesContent": ["// NOTE: This file is intentionally duplicated as addon-v8.ts. The two files\n// are identical except for the manager-api import path: Storybook v8 exposes\n// it at 'storybook/internal/manager-api' while v9+ use 'storybook/manager-api'.\n// No single path works across all three major versions (v8/v9/v10), and the\n// React hooks used here can't be cleanly injected to share an implementation,\n// so the duplication is kept explicit. Keep the two files in sync.\nimport { createElement, useEffect, useState } from 'react';\nimport { AddonPanel } from 'storybook/internal/components';\nimport {\n addons,\n types,\n useChannel,\n useParameter,\n useStorybookState,\n} from 'storybook/manager-api';\n\nconst ADDON_ID = 'happo';\nconst PANEL_ID = `${ADDON_ID}/panel`;\n\ninterface FunctionParam {\n key: string;\n}\n\nfunction HappoPanel() {\n const happoParams = useParameter('happo', null);\n const state = useStorybookState();\n const emit = useChannel({});\n const [functionParams, setFunctionParams] = useState<Array<FunctionParam>>([]);\n\n useEffect(() => {\n function listen(event: { params: Array<FunctionParam> }) {\n setFunctionParams(event.params);\n }\n\n addons.getChannel().on('happo/functions/params', listen);\n\n return () => {\n addons.getChannel().off('happo/functions/params', listen);\n };\n }, [state.storyId]);\n\n return createElement(\n 'div',\n {\n style: {\n padding: 10,\n fontSize: 12,\n },\n },\n happoParams\n ? createElement(\n 'table',\n null,\n createElement(\n 'tbody',\n null,\n Object.keys(happoParams).map((key) => {\n const val = happoParams[key];\n\n return createElement(\n 'tr',\n { key: key },\n createElement('td', null, createElement('code', null, `${key}:`)),\n createElement(\n 'td',\n null,\n createElement('code', null, JSON.stringify(val)),\n ),\n );\n }),\n functionParams.map((param) => {\n return createElement(\n 'tr',\n { key: param.key },\n createElement(\n 'td',\n null,\n createElement('code', null, `${param.key}:`),\n ),\n createElement(\n 'td',\n null,\n createElement(\n 'button',\n {\n onClick: () =>\n emit('happo/functions/invoke', {\n storyId: state.storyId,\n funcName: param.key,\n }),\n },\n 'Invoke',\n ),\n ),\n );\n }),\n ),\n )\n : createElement('div', null, 'No happo params for this story'),\n );\n}\n\naddons.register(ADDON_ID, () => {\n addons.add(PANEL_ID, {\n type: types.PANEL,\n title: 'Happo',\n render: ({ active }) => {\n return createElement(AddonPanel, {\n active: active ?? false,\n children: createElement(HappoPanel, null),\n });\n },\n });\n});\n"],
5
+ "mappings": ";AAMA,SAAS,eAAe,WAAW,gBAAgB;AACnD,SAAS,kBAAkB;AAC3B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,IAAM,WAAW;AACjB,IAAM,WAAW,GAAG,QAAQ;AAM5B,SAAS,aAAa;AACpB,QAAM,cAAc,aAAa,SAAS,IAAI;AAC9C,QAAM,QAAQ,kBAAkB;AAChC,QAAM,OAAO,WAAW,CAAC,CAAC;AAC1B,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAA+B,CAAC,CAAC;AAE7E,YAAU,MAAM;AACd,aAAS,OAAO,OAAyC;AACvD,wBAAkB,MAAM,MAAM;AAAA,IAChC;AAEA,WAAO,WAAW,EAAE,GAAG,0BAA0B,MAAM;AAEvD,WAAO,MAAM;AACX,aAAO,WAAW,EAAE,IAAI,0BAA0B,MAAM;AAAA,IAC1D;AAAA,EACF,GAAG,CAAC,MAAM,OAAO,CAAC;AAElB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,QACL,SAAS;AAAA,QACT,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,IACA,cACI;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA,OAAO,KAAK,WAAW,EAAE,IAAI,CAAC,QAAQ;AACpC,gBAAM,MAAM,YAAY,GAAG;AAE3B,iBAAO;AAAA,YACL;AAAA,YACA,EAAE,IAAS;AAAA,YACX,cAAc,MAAM,MAAM,cAAc,QAAQ,MAAM,GAAG,GAAG,GAAG,CAAC;AAAA,YAChE;AAAA,cACE;AAAA,cACA;AAAA,cACA,cAAc,QAAQ,MAAM,KAAK,UAAU,GAAG,CAAC;AAAA,YACjD;AAAA,UACF;AAAA,QACF,CAAC;AAAA,QACD,eAAe,IAAI,CAAC,UAAU;AAC5B,iBAAO;AAAA,YACL;AAAA,YACA,EAAE,KAAK,MAAM,IAAI;AAAA,YACjB;AAAA,cACE;AAAA,cACA;AAAA,cACA,cAAc,QAAQ,MAAM,GAAG,MAAM,GAAG,GAAG;AAAA,YAC7C;AAAA,YACA;AAAA,cACE;AAAA,cACA;AAAA,cACA;AAAA,gBACE;AAAA,gBACA;AAAA,kBACE,SAAS,MACP,KAAK,0BAA0B;AAAA,oBAC7B,SAAS,MAAM;AAAA,oBACf,UAAU,MAAM;AAAA,kBAClB,CAAC;AAAA,gBACL;AAAA,gBACA;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,IACA,cAAc,OAAO,MAAM,gCAAgC;AAAA,EACjE;AACF;AAEA,OAAO,SAAS,UAAU,MAAM;AAC9B,SAAO,IAAI,UAAU;AAAA,IACnB,MAAM,MAAM;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ,CAAC,EAAE,OAAO,MAAM;AACtB,aAAO,cAAc,YAAY;AAAA,QAC/B,QAAQ,UAAU;AAAA,QAClB,UAAU,cAAc,YAAY,IAAI;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH,CAAC;",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,4 @@
1
- import { makeDecorator } from 'storybook/preview-api';
1
+ import { makeDecorator } from 'storybook/internal/preview-api';
2
2
  export declare const withHappo: ReturnType<typeof makeDecorator>;
3
3
  export default withHappo;
4
4
  //# sourceMappingURL=decorator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decorator.d.ts","sourceRoot":"","sources":["../../../src/storybook/browser/decorator.ts"],"names":[],"mappings":"AACA,OAAO,EAAU,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAmE9D,eAAO,MAAM,SAAS,EAAE,UAAU,CAAC,OAAO,aAAa,CASrD,CAAC;AAEH,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"decorator.d.ts","sourceRoot":"","sources":["../../../src/storybook/browser/decorator.ts"],"names":[],"mappings":"AACA,OAAO,EAAU,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAmEvE,eAAO,MAAM,SAAS,EAAE,UAAU,CAAC,OAAO,aAAa,CASrD,CAAC;AAEH,eAAe,SAAS,CAAC"}
@@ -4,7 +4,7 @@ import {
4
4
 
5
5
  // src/storybook/browser/decorator.ts
6
6
  import { createElement, useEffect } from "react";
7
- import { addons, makeDecorator } from "storybook/preview-api";
7
+ import { addons, makeDecorator } from "storybook/internal/preview-api";
8
8
  function HappoDecorator({
9
9
  params,
10
10
  children
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/storybook/browser/decorator.ts"],
4
- "sourcesContent": ["import { createElement, type ReactNode, useEffect } from 'react';\nimport { addons, makeDecorator } from 'storybook/preview-api';\n\nimport { SB_ROOT_ELEMENT_SELECTOR } from './constants.ts';\n\ninterface HappoParams {\n [key: string]: ((args: { rootElement: Element | null }) => unknown) | unknown;\n}\n\nfunction HappoDecorator({\n params,\n children,\n}: {\n params: HappoParams | null;\n children: ReactNode;\n}) {\n useEffect(() => {\n if (!params) {\n return;\n }\n\n const channel = addons.getChannel();\n async function listen({ funcName }: { funcName: string }) {\n const rootElement = document.querySelector(SB_ROOT_ELEMENT_SELECTOR);\n if (params && params[funcName] && typeof params[funcName] === 'function') {\n const result = params[funcName]({ rootElement });\n\n if (result instanceof Promise) {\n console.log(`Invoked Happo function \\`${funcName}\\`. Awaiting result...`);\n const finalResult = await result;\n console.log(\n `Async result of Happo function \\`${funcName}\\`:`,\n finalResult,\n );\n } else {\n console.log(\n `Invoked Happo function \\`${funcName}\\`. Return value:`,\n result,\n );\n }\n } else {\n console.warn(`Happo function ${funcName} not found.`);\n }\n }\n\n channel.on('happo/functions/invoke', listen);\n channel.emit('happo/functions/params', {\n params: Object.keys(params)\n .map((key) => {\n if (typeof params[key] === 'function') {\n return {\n key,\n value: params[key],\n };\n }\n return null;\n })\n .filter(Boolean),\n });\n\n return () => {\n channel.off('happo/functions/invoke', listen);\n };\n }, [params]);\n\n return children;\n}\n\nexport const withHappo: ReturnType<typeof makeDecorator> = makeDecorator({\n name: 'withHappo',\n parameterName: 'happo',\n wrapper: (Story, context) => {\n return createElement(HappoDecorator, {\n params: context.parameters.happo || null,\n children: createElement(Story as React.ComponentType, null),\n });\n },\n});\n\nexport default withHappo;\n"],
4
+ "sourcesContent": ["import { createElement, type ReactNode, useEffect } from 'react';\nimport { addons, makeDecorator } from 'storybook/internal/preview-api';\n\nimport { SB_ROOT_ELEMENT_SELECTOR } from './constants.ts';\n\ninterface HappoParams {\n [key: string]: ((args: { rootElement: Element | null }) => unknown) | unknown;\n}\n\nfunction HappoDecorator({\n params,\n children,\n}: {\n params: HappoParams | null;\n children: ReactNode;\n}) {\n useEffect(() => {\n if (!params) {\n return;\n }\n\n const channel = addons.getChannel();\n async function listen({ funcName }: { funcName: string }) {\n const rootElement = document.querySelector(SB_ROOT_ELEMENT_SELECTOR);\n if (params && params[funcName] && typeof params[funcName] === 'function') {\n const result = params[funcName]({ rootElement });\n\n if (result instanceof Promise) {\n console.log(`Invoked Happo function \\`${funcName}\\`. Awaiting result...`);\n const finalResult = await result;\n console.log(\n `Async result of Happo function \\`${funcName}\\`:`,\n finalResult,\n );\n } else {\n console.log(\n `Invoked Happo function \\`${funcName}\\`. Return value:`,\n result,\n );\n }\n } else {\n console.warn(`Happo function ${funcName} not found.`);\n }\n }\n\n channel.on('happo/functions/invoke', listen);\n channel.emit('happo/functions/params', {\n params: Object.keys(params)\n .map((key) => {\n if (typeof params[key] === 'function') {\n return {\n key,\n value: params[key],\n };\n }\n return null;\n })\n .filter(Boolean),\n });\n\n return () => {\n channel.off('happo/functions/invoke', listen);\n };\n }, [params]);\n\n return children;\n}\n\nexport const withHappo: ReturnType<typeof makeDecorator> = makeDecorator({\n name: 'withHappo',\n parameterName: 'happo',\n wrapper: (Story, context) => {\n return createElement(HappoDecorator, {\n params: context.parameters.happo || null,\n children: createElement(Story as React.ComponentType, null),\n });\n },\n});\n\nexport default withHappo;\n"],
5
5
  "mappings": ";;;;;AAAA,SAAS,eAA+B,iBAAiB;AACzD,SAAS,QAAQ,qBAAqB;AAQtC,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AACF,GAGG;AACD,YAAU,MAAM;AACd,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AAEA,UAAM,UAAU,OAAO,WAAW;AAClC,mBAAe,OAAO,EAAE,SAAS,GAAyB;AACxD,YAAM,cAAc,SAAS,cAAc,wBAAwB;AACnE,UAAI,UAAU,OAAO,QAAQ,KAAK,OAAO,OAAO,QAAQ,MAAM,YAAY;AACxE,cAAM,SAAS,OAAO,QAAQ,EAAE,EAAE,YAAY,CAAC;AAE/C,YAAI,kBAAkB,SAAS;AAC7B,kBAAQ,IAAI,4BAA4B,QAAQ,wBAAwB;AACxE,gBAAM,cAAc,MAAM;AAC1B,kBAAQ;AAAA,YACN,oCAAoC,QAAQ;AAAA,YAC5C;AAAA,UACF;AAAA,QACF,OAAO;AACL,kBAAQ;AAAA,YACN,4BAA4B,QAAQ;AAAA,YACpC;AAAA,UACF;AAAA,QACF;AAAA,MACF,OAAO;AACL,gBAAQ,KAAK,kBAAkB,QAAQ,aAAa;AAAA,MACtD;AAAA,IACF;AAEA,YAAQ,GAAG,0BAA0B,MAAM;AAC3C,YAAQ,KAAK,0BAA0B;AAAA,MACrC,QAAQ,OAAO,KAAK,MAAM,EACvB,IAAI,CAAC,QAAQ;AACZ,YAAI,OAAO,OAAO,GAAG,MAAM,YAAY;AACrC,iBAAO;AAAA,YACL;AAAA,YACA,OAAO,OAAO,GAAG;AAAA,UACnB;AAAA,QACF;AACA,eAAO;AAAA,MACT,CAAC,EACA,OAAO,OAAO;AAAA,IACnB,CAAC;AAED,WAAO,MAAM;AACX,cAAQ,IAAI,0BAA0B,MAAM;AAAA,IAC9C;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,SAAO;AACT;AAEO,IAAM,YAA8C,cAAc;AAAA,EACvE,MAAM;AAAA,EACN,eAAe;AAAA,EACf,SAAS,CAAC,OAAO,YAAY;AAC3B,WAAO,cAAc,gBAAgB;AAAA,MACnC,QAAQ,QAAQ,WAAW,SAAS;AAAA,MACpC,UAAU,cAAc,OAA8B,IAAI;AAAA,IAC5D,CAAC;AAAA,EACH;AACF,CAAC;AAED,IAAO,oBAAQ;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,89 @@
1
+ // src/storybook/getStorybookVersionFromPackageJson.ts
2
+ import fs from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import path from "node:path";
5
+ import * as walk from "empathic/walk";
6
+ function readVersionFrom(filePath) {
7
+ try {
8
+ return JSON.parse(fs.readFileSync(filePath, "utf8")).version;
9
+ } catch {
10
+ return void 0;
11
+ }
12
+ }
13
+ function findPackageJsonForEntryPath(entryPath, pkgName) {
14
+ for (const dir of walk.up(path.dirname(entryPath))) {
15
+ const candidate = path.join(dir, "package.json");
16
+ try {
17
+ const parsed = JSON.parse(fs.readFileSync(candidate, "utf8"));
18
+ if (parsed.name === pkgName) {
19
+ return candidate;
20
+ }
21
+ } catch {
22
+ }
23
+ }
24
+ return void 0;
25
+ }
26
+ function readInstalledVersion(pkg, projectRoot) {
27
+ const requireFromProject = createRequire(
28
+ path.join(projectRoot, "package.json")
29
+ );
30
+ try {
31
+ const version = readVersionFrom(
32
+ requireFromProject.resolve(`${pkg}/package.json`)
33
+ );
34
+ if (version) {
35
+ return version;
36
+ }
37
+ } catch {
38
+ }
39
+ try {
40
+ const entryPath = requireFromProject.resolve(pkg);
41
+ const pkgJsonPath = findPackageJsonForEntryPath(entryPath, pkg);
42
+ if (pkgJsonPath) {
43
+ const version = readVersionFrom(pkgJsonPath);
44
+ if (version) {
45
+ return version;
46
+ }
47
+ }
48
+ } catch {
49
+ }
50
+ return readVersionFrom(
51
+ path.join(projectRoot, "node_modules", pkg, "package.json")
52
+ );
53
+ }
54
+ function getStorybookVersionFromPackageJson(packageJsonPath = path.join(process.cwd(), "package.json")) {
55
+ const data = fs.readFileSync(packageJsonPath, "utf8");
56
+ const packageJson = JSON.parse(data);
57
+ const combinedDependencies = {
58
+ ...packageJson.dependencies,
59
+ ...packageJson.devDependencies
60
+ };
61
+ const storybookPackage = [
62
+ "storybook",
63
+ "@storybook/react",
64
+ "@storybook/angular",
65
+ "@storybook/vue"
66
+ ].find((pkg) => combinedDependencies[pkg]);
67
+ if (!storybookPackage) {
68
+ throw new Error("Storybook is not listed as a dependency in package.json");
69
+ }
70
+ const declaredVersion = combinedDependencies[storybookPackage];
71
+ const declaredMatch = declaredVersion.match(/\d+/);
72
+ if (declaredMatch) {
73
+ return Number.parseInt(declaredMatch[0], 10);
74
+ }
75
+ const projectRoot = path.dirname(packageJsonPath);
76
+ const installedVersion = readInstalledVersion(storybookPackage, projectRoot);
77
+ const installedMatch = installedVersion?.match(/\d+/);
78
+ if (installedMatch) {
79
+ return Number.parseInt(installedMatch[0], 10);
80
+ }
81
+ throw new Error(
82
+ `Unable to determine installed version of ${storybookPackage} (found "${declaredVersion}" in ${packageJsonPath}). Tried resolving from ${projectRoot} and reading ${path.join(projectRoot, "node_modules", storybookPackage, "package.json")}. Ensure dependencies are installed and that ${storybookPackage} is resolvable from that project root.`
83
+ );
84
+ }
85
+
86
+ export {
87
+ getStorybookVersionFromPackageJson
88
+ };
89
+ //# sourceMappingURL=chunk-YBRVICYB.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/storybook/getStorybookVersionFromPackageJson.ts"],
4
+ "sourcesContent": ["import fs from 'node:fs';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\n\nimport * as walk from 'empathic/walk';\n\nfunction readVersionFrom(filePath: string): string | undefined {\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf8')).version;\n } catch {\n return undefined;\n }\n}\n\nfunction findPackageJsonForEntryPath(\n entryPath: string,\n pkgName: string,\n): string | undefined {\n // Walk up from a resolved entry file to the nearest package.json whose\n // `name` matches `pkgName`. Node's resolution always places the entry inside\n // the package's own tree (even under pnpm's .pnpm virtual store or Yarn\n // PnP's zipfs), so this reliably finds the correct root.\n for (const dir of walk.up(path.dirname(entryPath))) {\n const candidate = path.join(dir, 'package.json');\n try {\n const parsed = JSON.parse(fs.readFileSync(candidate, 'utf8'));\n if (parsed.name === pkgName) {\n return candidate;\n }\n } catch {\n // not a readable package.json here; keep walking up\n }\n }\n\n return undefined;\n}\n\nfunction readInstalledVersion(\n pkg: string,\n projectRoot: string,\n): string | undefined {\n // Prefer Node's module resolution so we work with every layout that Node\n // itself understands: flat node_modules (npm/yarn classic), pnpm's symlinked\n // tree, hoisted packages in parent node_modules, and Yarn Plug'n'Play when\n // the process has PnP hooks installed.\n const requireFromProject = createRequire(\n path.join(projectRoot, 'package.json'),\n );\n\n // Tier 1: resolve `${pkg}/package.json` directly. The happy path for most\n // packages regardless of layout.\n try {\n const version = readVersionFrom(\n requireFromProject.resolve(`${pkg}/package.json`),\n );\n if (version) {\n return version;\n }\n } catch {\n // Packages whose `exports` field does not list `./package.json` make\n // require.resolve throw `ERR_PACKAGE_PATH_NOT_EXPORTED` even when the\n // file exists. Fall through.\n }\n\n // Tier 2: resolve the package's main entry and walk up to its package.json.\n // Covers the combination of a restrictive `exports` field and a hoisted\n // install (parent node_modules, pnpm virtual store, Yarn PnP zipfs), where\n // neither tier 1 nor the direct lookup below would work.\n try {\n const entryPath = requireFromProject.resolve(pkg);\n const pkgJsonPath = findPackageJsonForEntryPath(entryPath, pkg);\n if (pkgJsonPath) {\n const version = readVersionFrom(pkgJsonPath);\n if (version) {\n return version;\n }\n }\n } catch {\n // Fall through to the direct node_modules lookup.\n }\n\n // Tier 3: read node_modules/<pkg>/package.json directly. Belt-and-suspenders\n // for cases where the file exists on disk but require.resolve cannot reach\n // it (e.g. both `.` and `./package.json` hidden behind a restrictive\n // exports map).\n return readVersionFrom(\n path.join(projectRoot, 'node_modules', pkg, 'package.json'),\n );\n}\n\nexport default function getStorybookVersionFromPackageJson(\n packageJsonPath: string = path.join(process.cwd(), 'package.json'),\n): number {\n const data = fs.readFileSync(packageJsonPath, 'utf8');\n const packageJson = JSON.parse(data);\n\n const combinedDependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const storybookPackage = [\n 'storybook',\n '@storybook/react',\n '@storybook/angular',\n '@storybook/vue',\n ].find((pkg) => combinedDependencies[pkg]);\n\n if (!storybookPackage) {\n throw new Error('Storybook is not listed as a dependency in package.json');\n }\n\n const declaredVersion: string = combinedDependencies[storybookPackage];\n const declaredMatch = declaredVersion.match(/\\d+/);\n if (declaredMatch) {\n return Number.parseInt(declaredMatch[0], 10);\n }\n\n // The declared dependency is not a plain semver range. This happens with\n // pnpm catalogs (\"catalog:\", \"catalog:foo\"), workspace protocols\n // (\"workspace:*\"), and other non-semver specifiers (\"link:\", \"file:\", etc.).\n // Fall back to the version from the installed package in node_modules.\n const projectRoot = path.dirname(packageJsonPath);\n const installedVersion = readInstalledVersion(storybookPackage, projectRoot);\n const installedMatch = installedVersion?.match(/\\d+/);\n if (installedMatch) {\n return Number.parseInt(installedMatch[0], 10);\n }\n\n throw new Error(\n `Unable to determine installed version of ${storybookPackage} (found \"${declaredVersion}\" in ${packageJsonPath}). ` +\n `Tried resolving from ${projectRoot} and reading ${path.join(projectRoot, 'node_modules', storybookPackage, 'package.json')}. ` +\n `Ensure dependencies are installed and that ${storybookPackage} is resolvable from that project root.`,\n );\n}\n"],
5
+ "mappings": ";AAAA,OAAO,QAAQ;AACf,SAAS,qBAAqB;AAC9B,OAAO,UAAU;AAEjB,YAAY,UAAU;AAEtB,SAAS,gBAAgB,UAAsC;AAC7D,MAAI;AACF,WAAO,KAAK,MAAM,GAAG,aAAa,UAAU,MAAM,CAAC,EAAE;AAAA,EACvD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,4BACP,WACA,SACoB;AAKpB,aAAW,OAAY,QAAG,KAAK,QAAQ,SAAS,CAAC,GAAG;AAClD,UAAM,YAAY,KAAK,KAAK,KAAK,cAAc;AAC/C,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,GAAG,aAAa,WAAW,MAAM,CAAC;AAC5D,UAAI,OAAO,SAAS,SAAS;AAC3B,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,qBACP,KACA,aACoB;AAKpB,QAAM,qBAAqB;AAAA,IACzB,KAAK,KAAK,aAAa,cAAc;AAAA,EACvC;AAIA,MAAI;AACF,UAAM,UAAU;AAAA,MACd,mBAAmB,QAAQ,GAAG,GAAG,eAAe;AAAA,IAClD;AACA,QAAI,SAAS;AACX,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAIR;AAMA,MAAI;AACF,UAAM,YAAY,mBAAmB,QAAQ,GAAG;AAChD,UAAM,cAAc,4BAA4B,WAAW,GAAG;AAC9D,QAAI,aAAa;AACf,YAAM,UAAU,gBAAgB,WAAW;AAC3C,UAAI,SAAS;AACX,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAMA,SAAO;AAAA,IACL,KAAK,KAAK,aAAa,gBAAgB,KAAK,cAAc;AAAA,EAC5D;AACF;AAEe,SAAR,mCACL,kBAA0B,KAAK,KAAK,QAAQ,IAAI,GAAG,cAAc,GACzD;AACR,QAAM,OAAO,GAAG,aAAa,iBAAiB,MAAM;AACpD,QAAM,cAAc,KAAK,MAAM,IAAI;AAEnC,QAAM,uBAAuB;AAAA,IAC3B,GAAG,YAAY;AAAA,IACf,GAAG,YAAY;AAAA,EACjB;AAEA,QAAM,mBAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,CAAC,QAAQ,qBAAqB,GAAG,CAAC;AAEzC,MAAI,CAAC,kBAAkB;AACrB,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AAEA,QAAM,kBAA0B,qBAAqB,gBAAgB;AACrE,QAAM,gBAAgB,gBAAgB,MAAM,KAAK;AACjD,MAAI,eAAe;AACjB,WAAO,OAAO,SAAS,cAAc,CAAC,GAAG,EAAE;AAAA,EAC7C;AAMA,QAAM,cAAc,KAAK,QAAQ,eAAe;AAChD,QAAM,mBAAmB,qBAAqB,kBAAkB,WAAW;AAC3E,QAAM,iBAAiB,kBAAkB,MAAM,KAAK;AACpD,MAAI,gBAAgB;AAClB,WAAO,OAAO,SAAS,eAAe,CAAC,GAAG,EAAE;AAAA,EAC9C;AAEA,QAAM,IAAI;AAAA,IACR,4CAA4C,gBAAgB,YAAY,eAAe,QAAQ,eAAe,2BACpF,WAAW,gBAAgB,KAAK,KAAK,aAAa,gBAAgB,kBAAkB,cAAc,CAAC,gDAC7E,gBAAgB;AAAA,EAClE;AACF;",
6
+ "names": []
7
+ }
@@ -1,7 +1,11 @@
1
+ import {
2
+ getStorybookVersionFromPackageJson
3
+ } from "./chunk-YBRVICYB.js";
4
+
1
5
  // src/storybook/index.ts
2
6
  import { spawn } from "node:child_process";
3
- import fs3 from "node:fs";
4
- import path4 from "node:path";
7
+ import fs2 from "node:fs";
8
+ import path3 from "node:path";
5
9
 
6
10
  // src/isomorphic/parseSkip.ts
7
11
  function toSkipSet(items) {
@@ -57,93 +61,8 @@ function getStorybookBuildCommandParts(packageJsonPath = path.join(process.cwd()
57
61
  return ["storybook", "build"];
58
62
  }
59
63
 
60
- // src/storybook/getStorybookVersionFromPackageJson.ts
61
- import fs2 from "node:fs";
62
- import { createRequire } from "node:module";
63
- import path2 from "node:path";
64
- import * as walk from "empathic/walk";
65
- function readVersionFrom(filePath) {
66
- try {
67
- return JSON.parse(fs2.readFileSync(filePath, "utf8")).version;
68
- } catch {
69
- return void 0;
70
- }
71
- }
72
- function findPackageJsonForEntryPath(entryPath, pkgName) {
73
- for (const dir of walk.up(path2.dirname(entryPath))) {
74
- const candidate = path2.join(dir, "package.json");
75
- try {
76
- const parsed = JSON.parse(fs2.readFileSync(candidate, "utf8"));
77
- if (parsed.name === pkgName) {
78
- return candidate;
79
- }
80
- } catch {
81
- }
82
- }
83
- return void 0;
84
- }
85
- function readInstalledVersion(pkg, projectRoot) {
86
- const requireFromProject = createRequire(
87
- path2.join(projectRoot, "package.json")
88
- );
89
- try {
90
- const version = readVersionFrom(
91
- requireFromProject.resolve(`${pkg}/package.json`)
92
- );
93
- if (version) {
94
- return version;
95
- }
96
- } catch {
97
- }
98
- try {
99
- const entryPath = requireFromProject.resolve(pkg);
100
- const pkgJsonPath = findPackageJsonForEntryPath(entryPath, pkg);
101
- if (pkgJsonPath) {
102
- const version = readVersionFrom(pkgJsonPath);
103
- if (version) {
104
- return version;
105
- }
106
- }
107
- } catch {
108
- }
109
- return readVersionFrom(
110
- path2.join(projectRoot, "node_modules", pkg, "package.json")
111
- );
112
- }
113
- function getStorybookVersionFromPackageJson(packageJsonPath = path2.join(process.cwd(), "package.json")) {
114
- const data = fs2.readFileSync(packageJsonPath, "utf8");
115
- const packageJson = JSON.parse(data);
116
- const combinedDependencies = {
117
- ...packageJson.dependencies,
118
- ...packageJson.devDependencies
119
- };
120
- const storybookPackage = [
121
- "storybook",
122
- "@storybook/react",
123
- "@storybook/angular",
124
- "@storybook/vue"
125
- ].find((pkg) => combinedDependencies[pkg]);
126
- if (!storybookPackage) {
127
- throw new Error("Storybook is not listed as a dependency in package.json");
128
- }
129
- const declaredVersion = combinedDependencies[storybookPackage];
130
- const declaredMatch = declaredVersion.match(/\d+/);
131
- if (declaredMatch) {
132
- return Number.parseInt(declaredMatch[0], 10);
133
- }
134
- const projectRoot = path2.dirname(packageJsonPath);
135
- const installedVersion = readInstalledVersion(storybookPackage, projectRoot);
136
- const installedMatch = installedVersion?.match(/\d+/);
137
- if (installedMatch) {
138
- return Number.parseInt(installedMatch[0], 10);
139
- }
140
- throw new Error(
141
- `Unable to determine installed version of ${storybookPackage} (found "${declaredVersion}" in ${packageJsonPath}). Tried resolving from ${projectRoot} and reading ${path2.join(projectRoot, "node_modules", storybookPackage, "package.json")}. Ensure dependencies are installed and that ${storybookPackage} is resolvable from that project root.`
142
- );
143
- }
144
-
145
64
  // src/storybook/resolveStoryFileItems.ts
146
- import path3 from "node:path";
65
+ import path2 from "node:path";
147
66
  function resolveStoryFileItems(skip, entries) {
148
67
  const fileToComponents = /* @__PURE__ */ new Map();
149
68
  for (const entry of Object.values(entries)) {
@@ -165,9 +84,9 @@ function resolveStoryFileItems(skip, entries) {
165
84
  const normalizedFile = normalizeImportPath(item.storyFile);
166
85
  let components = fileToComponents.get(normalizedFile);
167
86
  if (!components) {
168
- const resolvedFile = path3.resolve(item.storyFile);
87
+ const resolvedFile = path2.resolve(item.storyFile);
169
88
  for (const [normalizedImport, titles] of fileToComponents) {
170
- if (path3.resolve(normalizedImport) === resolvedFile) {
89
+ if (path2.resolve(normalizedImport) === resolvedFile) {
171
90
  components = titles;
172
91
  break;
173
92
  }
@@ -193,9 +112,9 @@ function normalizeImportPath(p) {
193
112
  var { HAPPO_DEBUG: HAPPO_DEBUG2 } = process.env;
194
113
  function resolveBuildCommandParts() {
195
114
  const version = getStorybookVersionFromPackageJson();
196
- if (version < 9) {
115
+ if (version < 8) {
197
116
  throw new Error(
198
- `Storybook v${version} is not supported. Please update storybook to v9 or later.`
117
+ `Storybook v${version} is not supported. Please update storybook to v8 or later.`
199
118
  );
200
119
  }
201
120
  return getStorybookBuildCommandParts();
@@ -205,7 +124,7 @@ async function buildStorybook({
205
124
  staticDir,
206
125
  outputDir
207
126
  }) {
208
- await fs3.promises.rm(outputDir, { recursive: true, force: true });
127
+ await fs2.promises.rm(outputDir, { recursive: true, force: true });
209
128
  const buildCommandParts = resolveBuildCommandParts();
210
129
  if (!buildCommandParts[0]) {
211
130
  throw new Error("Failed to resolve build command parts");
@@ -220,7 +139,7 @@ async function buildStorybook({
220
139
  if (staticDir) {
221
140
  params.push("--static-dir", staticDir);
222
141
  }
223
- let binary = fs3.existsSync("yarn.lock") ? "yarn" : "npx";
142
+ let binary = fs2.existsSync("yarn.lock") ? "yarn" : "npx";
224
143
  if (buildCommandParts[0].includes("node_modules")) {
225
144
  binary = buildCommandParts[0];
226
145
  params.shift();
@@ -236,7 +155,7 @@ async function buildStorybook({
236
155
  spawned.on("exit", (code) => {
237
156
  if (code === 0) {
238
157
  try {
239
- fs3.unlinkSync(path4.join(outputDir, "project.json"));
158
+ fs2.unlinkSync(path3.join(outputDir, "project.json"));
240
159
  } catch (error) {
241
160
  console.warn(
242
161
  `Ignoring error when attempting to remove project.json: ${error}`
@@ -260,20 +179,20 @@ async function buildStorybookPackage({
260
179
  if (!usePrebuiltPackage) {
261
180
  await buildStorybook({ configDir, staticDir, outputDir });
262
181
  }
263
- const iframePath = path4.join(outputDir, "iframe.html");
264
- if (!fs3.existsSync(iframePath)) {
182
+ const iframePath = path3.join(outputDir, "iframe.html");
183
+ if (!fs2.existsSync(iframePath)) {
265
184
  throw new Error(
266
185
  "Failed to build static storybook package (missing iframe.html)"
267
186
  );
268
187
  }
269
188
  try {
270
- const iframeContent = await fs3.promises.readFile(iframePath, "utf8");
189
+ const iframeContent = await fs2.promises.readFile(iframePath, "utf8");
271
190
  let estimatedSnapsCount;
272
191
  let resolvedSkip;
273
192
  let resolvedOnly;
274
- const indexPath = path4.join(outputDir, "index.json");
193
+ const indexPath = path3.join(outputDir, "index.json");
275
194
  try {
276
- const indexContent = await fs3.promises.readFile(indexPath, "utf8");
195
+ const indexContent = await fs2.promises.readFile(indexPath, "utf8");
277
196
  const indexData = JSON.parse(indexContent);
278
197
  const entries = indexData.entries ?? indexData.stories ?? {};
279
198
  const storyEntries = Object.values(entries).filter((e) => e.type === "story");
@@ -329,7 +248,7 @@ async function buildStorybookPackage({
329
248
  resolvedOnly = componentOnly.length > 0 ? componentOnly : void 0;
330
249
  }
331
250
  }
332
- await fs3.promises.writeFile(
251
+ await fs2.promises.writeFile(
333
252
  iframePath,
334
253
  iframeContent.replace(
335
254
  "<head>",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../src/storybook/index.ts", "../../src/isomorphic/parseSkip.ts", "../../src/storybook/getStorybookBuildCommandParts.ts", "../../src/storybook/getStorybookVersionFromPackageJson.ts", "../../src/storybook/resolveStoryFileItems.ts"],
4
- "sourcesContent": ["import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport type { StorybookIntegration } from '../config/index.ts';\nimport { isInSkipSet, toSkipSet } from '../isomorphic/parseSkip.ts';\nimport type { OnlyItem, SkipItem } from '../isomorphic/types.ts';\nimport getStorybookBuildCommandParts from './getStorybookBuildCommandParts.ts';\nimport getStorybookVersionFromPackageJson from './getStorybookVersionFromPackageJson.ts';\nimport resolveStoryFileItems, { type StorybookIndexEntry } from './resolveStoryFileItems.ts';\n\nconst { HAPPO_DEBUG } = process.env;\n\nfunction resolveBuildCommandParts() {\n const version = getStorybookVersionFromPackageJson();\n\n if (version < 9) {\n throw new Error(\n `Storybook v${version} is not supported. Please update storybook to v9 or later.`,\n );\n }\n\n return getStorybookBuildCommandParts();\n}\n\nasync function buildStorybook({\n configDir,\n staticDir,\n outputDir,\n}: {\n configDir: string;\n staticDir?: string | undefined;\n outputDir: string;\n}): Promise<void> {\n await fs.promises.rm(outputDir, { recursive: true, force: true });\n\n const buildCommandParts = resolveBuildCommandParts();\n\n if (!buildCommandParts[0]) {\n throw new Error('Failed to resolve build command parts');\n }\n\n const params = [\n ...buildCommandParts,\n '--output-dir',\n outputDir,\n '--config-dir',\n configDir,\n ];\n\n if (staticDir) {\n params.push('--static-dir', staticDir);\n }\n\n let binary = fs.existsSync('yarn.lock') ? 'yarn' : 'npx';\n\n if (buildCommandParts[0].includes('node_modules')) {\n binary = buildCommandParts[0];\n params.shift(); // remove binary from params\n }\n\n if (HAPPO_DEBUG) {\n console.log(`[happo] Using build command \\`${binary} ${params.join(' ')}\\``);\n }\n\n return new Promise((resolve, reject) => {\n const spawned = spawn(binary, params, {\n stdio: 'inherit',\n shell: process.platform == 'win32',\n });\n\n spawned.on('exit', (code) => {\n if (code === 0) {\n try {\n fs.unlinkSync(path.join(outputDir, 'project.json'));\n } catch (error) {\n console.warn(\n `Ignoring error when attempting to remove project.json: ${error}`,\n );\n }\n resolve();\n } else {\n reject(new Error('Failed to build static storybook package'));\n }\n });\n });\n}\n\nexport interface BuildStorybookPackageResult {\n packageDir: string;\n estimatedSnapsCount?: number;\n resolvedSkip?: Array<{ component: string; variant?: string }>;\n}\n\nexport default async function buildStorybookPackage({\n configDir = '.storybook',\n staticDir,\n outputDir = '.out',\n usePrebuiltPackage = false,\n skip,\n only,\n}: Omit<StorybookIntegration, 'type'> & {\n skip?: Array<SkipItem>;\n only?: Array<OnlyItem>;\n}): Promise<BuildStorybookPackageResult> {\n if (!usePrebuiltPackage) {\n await buildStorybook({ configDir, staticDir, outputDir });\n }\n\n const iframePath = path.join(outputDir, 'iframe.html');\n if (!fs.existsSync(iframePath)) {\n throw new Error(\n 'Failed to build static storybook package (missing iframe.html)',\n );\n }\n\n try {\n const iframeContent = await fs.promises.readFile(iframePath, 'utf8');\n\n // Read index.json once to compute story count and resolve storyFile items.\n let estimatedSnapsCount: number | undefined;\n let resolvedSkip: Array<{ component: string; variant?: string }> | undefined;\n let resolvedOnly: Array<{ component: string }> | undefined;\n\n const indexPath = path.join(outputDir, 'index.json');\n try {\n const indexContent = await fs.promises.readFile(indexPath, 'utf8');\n const indexData = JSON.parse(indexContent) as {\n entries?: Record<string, StorybookIndexEntry>;\n stories?: Record<string, StorybookIndexEntry>;\n };\n const entries = indexData.entries ?? indexData.stories ?? {};\n\n const storyEntries = Object.values(entries).filter((e) => e.type === 'story');\n estimatedSnapsCount = storyEntries.length;\n\n if (skip !== undefined) {\n resolvedSkip = resolveStoryFileItems(skip, entries);\n // Adjust the count so auto-chunking reflects only the stories that\n // will actually be rendered (skipped examples don't need a chunk slot).\n const skipSet = toSkipSet(resolvedSkip);\n estimatedSnapsCount = storyEntries.filter(\n (e) => !isInSkipSet(skipSet, e.title ?? '', e.name ?? ''),\n ).length;\n }\n\n if (only !== undefined) {\n if (only.length === 0) {\n // Empty --only: nothing is rendered locally; every component is\n // borrowed from the baseline via an extends-report.\n const allComponents = new Set<string>();\n for (const e of storyEntries) {\n if (e.title) allComponents.add(e.title);\n }\n resolvedSkip = [...allComponents].map((component) => ({ component }));\n estimatedSnapsCount = 0;\n } else {\n resolvedOnly = resolveStoryFileItems(only as Array<SkipItem>, entries).map(\n ({ component }) => ({ component }),\n );\n if (resolvedOnly.length === 0) {\n console.warn(\n '[HAPPO] --only: no matching stories found in Storybook index. Generating a full report instead.',\n );\n resolvedOnly = undefined;\n } else {\n // Adjust the count so auto-chunking reflects only the stories that\n // will actually be rendered (only matching examples need a chunk slot).\n const onlyComponents = new Set(resolvedOnly.map((item) => item.component));\n estimatedSnapsCount = storyEntries.filter((e) =>\n onlyComponents.has(e.title ?? ''),\n ).length;\n\n // Compute the complement: all components NOT in the only list.\n // These will be borrowed from the baseline via an extends-report.\n const allComponents = new Set<string>();\n for (const e of storyEntries) {\n if (e.title) allComponents.add(e.title);\n }\n resolvedSkip = [...allComponents]\n .filter((c) => !onlyComponents.has(c))\n .map((component) => ({ component }));\n }\n }\n }\n } catch (error) {\n console.warn('[HAPPO] Failed to read Storybook index.json:', error);\n if (skip !== undefined) {\n // Fall back to passing through only component-based items\n resolvedSkip = skip.filter(\n (item): item is { component: string; variant?: string } => 'component' in item,\n );\n }\n if (only !== undefined) {\n // Fall back to component-only items; if none remain, leave resolvedOnly\n // undefined so the browser-side filtering is disabled and a full report\n // is generated rather than an empty one.\n const componentOnly = only.filter(\n (item): item is { component: string } => 'component' in item,\n );\n resolvedOnly = componentOnly.length > 0 ? componentOnly : undefined;\n }\n }\n\n await fs.promises.writeFile(\n iframePath,\n iframeContent.replace(\n '<head>',\n `<head>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <script type=\"text/javascript\">window.__IS_HAPPO_RUN = true;</script>\n <script type=\"text/javascript\">window.happoSkipped = ${JSON.stringify(resolvedSkip ?? []).replaceAll(/<\\/script>/gi, String.raw`<\\/script>`)};</script>\n <script type=\"text/javascript\">window.happoOnly = ${JSON.stringify(resolvedOnly ?? null).replaceAll(/<\\/script>/gi, String.raw`<\\/script>`)};</script>\n `,\n ),\n );\n\n const result: BuildStorybookPackageResult = { packageDir: outputDir };\n if (estimatedSnapsCount != null) {\n result.estimatedSnapsCount = estimatedSnapsCount;\n }\n if (resolvedSkip !== undefined) {\n result.resolvedSkip = resolvedSkip;\n }\n return result;\n } catch (e) {\n console.error(e);\n throw e;\n }\n}\n", "import type { SkipItem } from './types.ts';\n\n/**\n * A pair of Sets used for O(1) skip lookups.\n * - [0]: component-only skips (match all variants of the component)\n * - [1]: component+variant skips (match a specific variant, keyed as \"component\\0variant\")\n */\nexport type SkipSet = readonly [componentOnly: Set<string>, componentVariant: Set<string>];\n\nfunction isSkipItem(item: unknown): item is SkipItem {\n if (typeof item !== 'object' || item === null) return false;\n const record = item as Record<string, unknown>;\n const hasComponent = typeof record['component'] === 'string';\n const hasStoryFile = typeof record['storyFile'] === 'string';\n if (hasComponent && hasStoryFile) return false;\n if (hasStoryFile) return record['variant'] === undefined;\n if (hasComponent) return record['variant'] === undefined || typeof record['variant'] === 'string';\n return false;\n}\n\n/**\n * Parses and validates a JSON string, returning an array of SkipItems.\n * Throws a TypeError if the JSON is invalid or not an array of SkipItems.\n */\nexport function validateSkip(json: string): Array<SkipItem> {\n const parsed: unknown = JSON.parse(json);\n if (!Array.isArray(parsed) || !parsed.every(isSkipItem)) {\n throw new TypeError(\n '--skip must be a JSON array of {component, variant?} or {storyFile} objects',\n );\n }\n return parsed;\n}\n\n/**\n * Parses a JSON string into an array of SkipItems. Returns an empty array on\n * any parse error or if the value is not a valid array of SkipItems.\n */\nexport function parseSkip(json?: string): Array<SkipItem> {\n if (!json) return [];\n try {\n return validateSkip(json);\n } catch {\n return [];\n }\n}\n\n/**\n * Converts an array of SkipItems into a SkipSet for efficient lookups.\n * Items with a `storyFile` key (unresolved) are silently ignored.\n */\nexport function toSkipSet(items: Array<SkipItem>): SkipSet {\n const componentOnly = new Set<string>();\n const componentVariant = new Set<string>();\n for (const item of items) {\n if (!('component' in item)) continue;\n const { component, variant } = item;\n if (variant === undefined) {\n componentOnly.add(component);\n } else {\n componentVariant.add(`${component}\\0${variant}`);\n }\n }\n return [componentOnly, componentVariant];\n}\n\n/**\n * Returns true if the given component+variant should be skipped according to\n * the SkipSet.\n */\nexport function isInSkipSet(\n [componentOnly, componentVariant]: SkipSet,\n component: string,\n variant: string,\n): boolean {\n return componentOnly.has(component) || componentVariant.has(`${component}\\0${variant}`);\n}\n", "import fs from 'node:fs';\nimport path from 'node:path';\n\nconst { HAPPO_DEBUG } = process.env;\n\nexport default function getStorybookBuildCommandParts(\n packageJsonPath: string = path.join(process.cwd(), 'package.json'),\n): [string, string] {\n try {\n const data = fs.readFileSync(packageJsonPath, 'utf8');\n const packageJson = JSON.parse(data);\n\n if (packageJson.scripts.storybook) {\n if (HAPPO_DEBUG) {\n console.log(\n '[happo] Found `storybook` script in package.json. Will attempt to use binary found at `node_modules/.bin/storybook` instead',\n );\n }\n\n const pathToStorybookCommand = path.join(\n process.cwd(),\n 'node_modules',\n '.bin',\n 'storybook',\n );\n\n if (fs.existsSync(pathToStorybookCommand)) {\n return [pathToStorybookCommand, 'build'];\n }\n }\n } catch (e) {\n if (HAPPO_DEBUG) {\n console.log(\n '[happo] Caught error when resolving Storybook build command parts. Will use default.',\n e,\n );\n }\n }\n\n return ['storybook', 'build'];\n}\n", "import fs from 'node:fs';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\n\nimport * as walk from 'empathic/walk';\n\nfunction readVersionFrom(filePath: string): string | undefined {\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf8')).version;\n } catch {\n return undefined;\n }\n}\n\nfunction findPackageJsonForEntryPath(\n entryPath: string,\n pkgName: string,\n): string | undefined {\n // Walk up from a resolved entry file to the nearest package.json whose\n // `name` matches `pkgName`. Node's resolution always places the entry inside\n // the package's own tree (even under pnpm's .pnpm virtual store or Yarn\n // PnP's zipfs), so this reliably finds the correct root.\n for (const dir of walk.up(path.dirname(entryPath))) {\n const candidate = path.join(dir, 'package.json');\n try {\n const parsed = JSON.parse(fs.readFileSync(candidate, 'utf8'));\n if (parsed.name === pkgName) {\n return candidate;\n }\n } catch {\n // not a readable package.json here; keep walking up\n }\n }\n\n return undefined;\n}\n\nfunction readInstalledVersion(\n pkg: string,\n projectRoot: string,\n): string | undefined {\n // Prefer Node's module resolution so we work with every layout that Node\n // itself understands: flat node_modules (npm/yarn classic), pnpm's symlinked\n // tree, hoisted packages in parent node_modules, and Yarn Plug'n'Play when\n // the process has PnP hooks installed.\n const requireFromProject = createRequire(\n path.join(projectRoot, 'package.json'),\n );\n\n // Tier 1: resolve `${pkg}/package.json` directly. The happy path for most\n // packages regardless of layout.\n try {\n const version = readVersionFrom(\n requireFromProject.resolve(`${pkg}/package.json`),\n );\n if (version) {\n return version;\n }\n } catch {\n // Packages whose `exports` field does not list `./package.json` make\n // require.resolve throw `ERR_PACKAGE_PATH_NOT_EXPORTED` even when the\n // file exists. Fall through.\n }\n\n // Tier 2: resolve the package's main entry and walk up to its package.json.\n // Covers the combination of a restrictive `exports` field and a hoisted\n // install (parent node_modules, pnpm virtual store, Yarn PnP zipfs), where\n // neither tier 1 nor the direct lookup below would work.\n try {\n const entryPath = requireFromProject.resolve(pkg);\n const pkgJsonPath = findPackageJsonForEntryPath(entryPath, pkg);\n if (pkgJsonPath) {\n const version = readVersionFrom(pkgJsonPath);\n if (version) {\n return version;\n }\n }\n } catch {\n // Fall through to the direct node_modules lookup.\n }\n\n // Tier 3: read node_modules/<pkg>/package.json directly. Belt-and-suspenders\n // for cases where the file exists on disk but require.resolve cannot reach\n // it (e.g. both `.` and `./package.json` hidden behind a restrictive\n // exports map).\n return readVersionFrom(\n path.join(projectRoot, 'node_modules', pkg, 'package.json'),\n );\n}\n\nexport default function getStorybookVersionFromPackageJson(\n packageJsonPath: string = path.join(process.cwd(), 'package.json'),\n): number {\n const data = fs.readFileSync(packageJsonPath, 'utf8');\n const packageJson = JSON.parse(data);\n\n const combinedDependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const storybookPackage = [\n 'storybook',\n '@storybook/react',\n '@storybook/angular',\n '@storybook/vue',\n ].find((pkg) => combinedDependencies[pkg]);\n\n if (!storybookPackage) {\n throw new Error('Storybook is not listed as a dependency in package.json');\n }\n\n const declaredVersion: string = combinedDependencies[storybookPackage];\n const declaredMatch = declaredVersion.match(/\\d+/);\n if (declaredMatch) {\n return Number.parseInt(declaredMatch[0], 10);\n }\n\n // The declared dependency is not a plain semver range. This happens with\n // pnpm catalogs (\"catalog:\", \"catalog:foo\"), workspace protocols\n // (\"workspace:*\"), and other non-semver specifiers (\"link:\", \"file:\", etc.).\n // Fall back to the version from the installed package in node_modules.\n const projectRoot = path.dirname(packageJsonPath);\n const installedVersion = readInstalledVersion(storybookPackage, projectRoot);\n const installedMatch = installedVersion?.match(/\\d+/);\n if (installedMatch) {\n return Number.parseInt(installedMatch[0], 10);\n }\n\n throw new Error(\n `Unable to determine installed version of ${storybookPackage} (found \"${declaredVersion}\" in ${packageJsonPath}). ` +\n `Tried resolving from ${projectRoot} and reading ${path.join(projectRoot, 'node_modules', storybookPackage, 'package.json')}. ` +\n `Ensure dependencies are installed and that ${storybookPackage} is resolvable from that project root.`,\n );\n}\n", "import path from 'node:path';\n\nimport type { SkipItem } from '../isomorphic/types.ts';\n\nexport interface StorybookIndexEntry {\n type: string;\n importPath?: string;\n title?: string;\n name?: string;\n}\n\n/**\n * Resolves `storyFile` skip items to component-based skip items using the\n * Storybook `index.json` entries. Items that already have a `component` are\n * passed through unchanged.\n *\n * Path matching is done by normalising both the `importPath` from the index\n * and the user-supplied `storyFile` (stripping a leading `./`), with an\n * absolute-path fallback via `path.resolve`.\n */\nexport default function resolveStoryFileItems(\n skip: Array<SkipItem>,\n entries: Record<string, StorybookIndexEntry>,\n): Array<{ component: string; variant?: string }> {\n const fileToComponents = new Map<string, Set<string>>();\n for (const entry of Object.values(entries)) {\n if (!entry.importPath || !entry.title) continue;\n const normalized = normalizeImportPath(entry.importPath);\n let set = fileToComponents.get(normalized);\n if (!set) {\n set = new Set();\n fileToComponents.set(normalized, set);\n }\n set.add(entry.title);\n }\n\n const resolved: Array<{ component: string; variant?: string }> = [];\n\n for (const item of skip) {\n if ('component' in item) {\n resolved.push(item);\n continue;\n }\n\n const normalizedFile = normalizeImportPath(item.storyFile);\n let components = fileToComponents.get(normalizedFile);\n\n if (!components) {\n // Fall back to absolute path comparison\n const resolvedFile = path.resolve(item.storyFile);\n for (const [normalizedImport, titles] of fileToComponents) {\n if (path.resolve(normalizedImport) === resolvedFile) {\n components = titles;\n break;\n }\n }\n }\n\n if (components) {\n for (const component of components) {\n resolved.push({ component });\n }\n } else {\n console.warn(\n `[HAPPO] Could not find any stories for storyFile '${item.storyFile}' in the Storybook index`,\n );\n }\n }\n\n return resolved;\n}\n\nfunction normalizeImportPath(p: string): string {\n return p.startsWith('./') ? p.slice(2) : p;\n}\n"],
5
- "mappings": "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",
6
- "names": ["fs", "path", "fs", "path", "path", "HAPPO_DEBUG", "fs", "path"]
3
+ "sources": ["../../src/storybook/index.ts", "../../src/isomorphic/parseSkip.ts", "../../src/storybook/getStorybookBuildCommandParts.ts", "../../src/storybook/resolveStoryFileItems.ts"],
4
+ "sourcesContent": ["import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport type { StorybookIntegration } from '../config/index.ts';\nimport { isInSkipSet, toSkipSet } from '../isomorphic/parseSkip.ts';\nimport type { OnlyItem, SkipItem } from '../isomorphic/types.ts';\nimport getStorybookBuildCommandParts from './getStorybookBuildCommandParts.ts';\nimport getStorybookVersionFromPackageJson from './getStorybookVersionFromPackageJson.ts';\nimport resolveStoryFileItems, { type StorybookIndexEntry } from './resolveStoryFileItems.ts';\n\nconst { HAPPO_DEBUG } = process.env;\n\nfunction resolveBuildCommandParts() {\n const version = getStorybookVersionFromPackageJson();\n\n if (version < 8) {\n throw new Error(\n `Storybook v${version} is not supported. Please update storybook to v8 or later.`,\n );\n }\n\n return getStorybookBuildCommandParts();\n}\n\nasync function buildStorybook({\n configDir,\n staticDir,\n outputDir,\n}: {\n configDir: string;\n staticDir?: string | undefined;\n outputDir: string;\n}): Promise<void> {\n await fs.promises.rm(outputDir, { recursive: true, force: true });\n\n const buildCommandParts = resolveBuildCommandParts();\n\n if (!buildCommandParts[0]) {\n throw new Error('Failed to resolve build command parts');\n }\n\n const params = [\n ...buildCommandParts,\n '--output-dir',\n outputDir,\n '--config-dir',\n configDir,\n ];\n\n if (staticDir) {\n params.push('--static-dir', staticDir);\n }\n\n let binary = fs.existsSync('yarn.lock') ? 'yarn' : 'npx';\n\n if (buildCommandParts[0].includes('node_modules')) {\n binary = buildCommandParts[0];\n params.shift(); // remove binary from params\n }\n\n if (HAPPO_DEBUG) {\n console.log(`[happo] Using build command \\`${binary} ${params.join(' ')}\\``);\n }\n\n return new Promise((resolve, reject) => {\n const spawned = spawn(binary, params, {\n stdio: 'inherit',\n shell: process.platform == 'win32',\n });\n\n spawned.on('exit', (code) => {\n if (code === 0) {\n try {\n fs.unlinkSync(path.join(outputDir, 'project.json'));\n } catch (error) {\n console.warn(\n `Ignoring error when attempting to remove project.json: ${error}`,\n );\n }\n resolve();\n } else {\n reject(new Error('Failed to build static storybook package'));\n }\n });\n });\n}\n\nexport interface BuildStorybookPackageResult {\n packageDir: string;\n estimatedSnapsCount?: number;\n resolvedSkip?: Array<{ component: string; variant?: string }>;\n}\n\nexport default async function buildStorybookPackage({\n configDir = '.storybook',\n staticDir,\n outputDir = '.out',\n usePrebuiltPackage = false,\n skip,\n only,\n}: Omit<StorybookIntegration, 'type'> & {\n skip?: Array<SkipItem>;\n only?: Array<OnlyItem>;\n}): Promise<BuildStorybookPackageResult> {\n if (!usePrebuiltPackage) {\n await buildStorybook({ configDir, staticDir, outputDir });\n }\n\n const iframePath = path.join(outputDir, 'iframe.html');\n if (!fs.existsSync(iframePath)) {\n throw new Error(\n 'Failed to build static storybook package (missing iframe.html)',\n );\n }\n\n try {\n const iframeContent = await fs.promises.readFile(iframePath, 'utf8');\n\n // Read index.json once to compute story count and resolve storyFile items.\n let estimatedSnapsCount: number | undefined;\n let resolvedSkip: Array<{ component: string; variant?: string }> | undefined;\n let resolvedOnly: Array<{ component: string }> | undefined;\n\n const indexPath = path.join(outputDir, 'index.json');\n try {\n const indexContent = await fs.promises.readFile(indexPath, 'utf8');\n const indexData = JSON.parse(indexContent) as {\n entries?: Record<string, StorybookIndexEntry>;\n stories?: Record<string, StorybookIndexEntry>;\n };\n const entries = indexData.entries ?? indexData.stories ?? {};\n\n const storyEntries = Object.values(entries).filter((e) => e.type === 'story');\n estimatedSnapsCount = storyEntries.length;\n\n if (skip !== undefined) {\n resolvedSkip = resolveStoryFileItems(skip, entries);\n // Adjust the count so auto-chunking reflects only the stories that\n // will actually be rendered (skipped examples don't need a chunk slot).\n const skipSet = toSkipSet(resolvedSkip);\n estimatedSnapsCount = storyEntries.filter(\n (e) => !isInSkipSet(skipSet, e.title ?? '', e.name ?? ''),\n ).length;\n }\n\n if (only !== undefined) {\n if (only.length === 0) {\n // Empty --only: nothing is rendered locally; every component is\n // borrowed from the baseline via an extends-report.\n const allComponents = new Set<string>();\n for (const e of storyEntries) {\n if (e.title) allComponents.add(e.title);\n }\n resolvedSkip = [...allComponents].map((component) => ({ component }));\n estimatedSnapsCount = 0;\n } else {\n resolvedOnly = resolveStoryFileItems(only as Array<SkipItem>, entries).map(\n ({ component }) => ({ component }),\n );\n if (resolvedOnly.length === 0) {\n console.warn(\n '[HAPPO] --only: no matching stories found in Storybook index. Generating a full report instead.',\n );\n resolvedOnly = undefined;\n } else {\n // Adjust the count so auto-chunking reflects only the stories that\n // will actually be rendered (only matching examples need a chunk slot).\n const onlyComponents = new Set(resolvedOnly.map((item) => item.component));\n estimatedSnapsCount = storyEntries.filter((e) =>\n onlyComponents.has(e.title ?? ''),\n ).length;\n\n // Compute the complement: all components NOT in the only list.\n // These will be borrowed from the baseline via an extends-report.\n const allComponents = new Set<string>();\n for (const e of storyEntries) {\n if (e.title) allComponents.add(e.title);\n }\n resolvedSkip = [...allComponents]\n .filter((c) => !onlyComponents.has(c))\n .map((component) => ({ component }));\n }\n }\n }\n } catch (error) {\n console.warn('[HAPPO] Failed to read Storybook index.json:', error);\n if (skip !== undefined) {\n // Fall back to passing through only component-based items\n resolvedSkip = skip.filter(\n (item): item is { component: string; variant?: string } => 'component' in item,\n );\n }\n if (only !== undefined) {\n // Fall back to component-only items; if none remain, leave resolvedOnly\n // undefined so the browser-side filtering is disabled and a full report\n // is generated rather than an empty one.\n const componentOnly = only.filter(\n (item): item is { component: string } => 'component' in item,\n );\n resolvedOnly = componentOnly.length > 0 ? componentOnly : undefined;\n }\n }\n\n await fs.promises.writeFile(\n iframePath,\n iframeContent.replace(\n '<head>',\n `<head>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <script type=\"text/javascript\">window.__IS_HAPPO_RUN = true;</script>\n <script type=\"text/javascript\">window.happoSkipped = ${JSON.stringify(resolvedSkip ?? []).replaceAll(/<\\/script>/gi, String.raw`<\\/script>`)};</script>\n <script type=\"text/javascript\">window.happoOnly = ${JSON.stringify(resolvedOnly ?? null).replaceAll(/<\\/script>/gi, String.raw`<\\/script>`)};</script>\n `,\n ),\n );\n\n const result: BuildStorybookPackageResult = { packageDir: outputDir };\n if (estimatedSnapsCount != null) {\n result.estimatedSnapsCount = estimatedSnapsCount;\n }\n if (resolvedSkip !== undefined) {\n result.resolvedSkip = resolvedSkip;\n }\n return result;\n } catch (e) {\n console.error(e);\n throw e;\n }\n}\n", "import type { SkipItem } from './types.ts';\n\n/**\n * A pair of Sets used for O(1) skip lookups.\n * - [0]: component-only skips (match all variants of the component)\n * - [1]: component+variant skips (match a specific variant, keyed as \"component\\0variant\")\n */\nexport type SkipSet = readonly [componentOnly: Set<string>, componentVariant: Set<string>];\n\nfunction isSkipItem(item: unknown): item is SkipItem {\n if (typeof item !== 'object' || item === null) return false;\n const record = item as Record<string, unknown>;\n const hasComponent = typeof record['component'] === 'string';\n const hasStoryFile = typeof record['storyFile'] === 'string';\n if (hasComponent && hasStoryFile) return false;\n if (hasStoryFile) return record['variant'] === undefined;\n if (hasComponent) return record['variant'] === undefined || typeof record['variant'] === 'string';\n return false;\n}\n\n/**\n * Parses and validates a JSON string, returning an array of SkipItems.\n * Throws a TypeError if the JSON is invalid or not an array of SkipItems.\n */\nexport function validateSkip(json: string): Array<SkipItem> {\n const parsed: unknown = JSON.parse(json);\n if (!Array.isArray(parsed) || !parsed.every(isSkipItem)) {\n throw new TypeError(\n '--skip must be a JSON array of {component, variant?} or {storyFile} objects',\n );\n }\n return parsed;\n}\n\n/**\n * Parses a JSON string into an array of SkipItems. Returns an empty array on\n * any parse error or if the value is not a valid array of SkipItems.\n */\nexport function parseSkip(json?: string): Array<SkipItem> {\n if (!json) return [];\n try {\n return validateSkip(json);\n } catch {\n return [];\n }\n}\n\n/**\n * Converts an array of SkipItems into a SkipSet for efficient lookups.\n * Items with a `storyFile` key (unresolved) are silently ignored.\n */\nexport function toSkipSet(items: Array<SkipItem>): SkipSet {\n const componentOnly = new Set<string>();\n const componentVariant = new Set<string>();\n for (const item of items) {\n if (!('component' in item)) continue;\n const { component, variant } = item;\n if (variant === undefined) {\n componentOnly.add(component);\n } else {\n componentVariant.add(`${component}\\0${variant}`);\n }\n }\n return [componentOnly, componentVariant];\n}\n\n/**\n * Returns true if the given component+variant should be skipped according to\n * the SkipSet.\n */\nexport function isInSkipSet(\n [componentOnly, componentVariant]: SkipSet,\n component: string,\n variant: string,\n): boolean {\n return componentOnly.has(component) || componentVariant.has(`${component}\\0${variant}`);\n}\n", "import fs from 'node:fs';\nimport path from 'node:path';\n\nconst { HAPPO_DEBUG } = process.env;\n\nexport default function getStorybookBuildCommandParts(\n packageJsonPath: string = path.join(process.cwd(), 'package.json'),\n): [string, string] {\n try {\n const data = fs.readFileSync(packageJsonPath, 'utf8');\n const packageJson = JSON.parse(data);\n\n if (packageJson.scripts.storybook) {\n if (HAPPO_DEBUG) {\n console.log(\n '[happo] Found `storybook` script in package.json. Will attempt to use binary found at `node_modules/.bin/storybook` instead',\n );\n }\n\n const pathToStorybookCommand = path.join(\n process.cwd(),\n 'node_modules',\n '.bin',\n 'storybook',\n );\n\n if (fs.existsSync(pathToStorybookCommand)) {\n return [pathToStorybookCommand, 'build'];\n }\n }\n } catch (e) {\n if (HAPPO_DEBUG) {\n console.log(\n '[happo] Caught error when resolving Storybook build command parts. Will use default.',\n e,\n );\n }\n }\n\n return ['storybook', 'build'];\n}\n", "import path from 'node:path';\n\nimport type { SkipItem } from '../isomorphic/types.ts';\n\nexport interface StorybookIndexEntry {\n type: string;\n importPath?: string;\n title?: string;\n name?: string;\n}\n\n/**\n * Resolves `storyFile` skip items to component-based skip items using the\n * Storybook `index.json` entries. Items that already have a `component` are\n * passed through unchanged.\n *\n * Path matching is done by normalising both the `importPath` from the index\n * and the user-supplied `storyFile` (stripping a leading `./`), with an\n * absolute-path fallback via `path.resolve`.\n */\nexport default function resolveStoryFileItems(\n skip: Array<SkipItem>,\n entries: Record<string, StorybookIndexEntry>,\n): Array<{ component: string; variant?: string }> {\n const fileToComponents = new Map<string, Set<string>>();\n for (const entry of Object.values(entries)) {\n if (!entry.importPath || !entry.title) continue;\n const normalized = normalizeImportPath(entry.importPath);\n let set = fileToComponents.get(normalized);\n if (!set) {\n set = new Set();\n fileToComponents.set(normalized, set);\n }\n set.add(entry.title);\n }\n\n const resolved: Array<{ component: string; variant?: string }> = [];\n\n for (const item of skip) {\n if ('component' in item) {\n resolved.push(item);\n continue;\n }\n\n const normalizedFile = normalizeImportPath(item.storyFile);\n let components = fileToComponents.get(normalizedFile);\n\n if (!components) {\n // Fall back to absolute path comparison\n const resolvedFile = path.resolve(item.storyFile);\n for (const [normalizedImport, titles] of fileToComponents) {\n if (path.resolve(normalizedImport) === resolvedFile) {\n components = titles;\n break;\n }\n }\n }\n\n if (components) {\n for (const component of components) {\n resolved.push({ component });\n }\n } else {\n console.warn(\n `[HAPPO] Could not find any stories for storyFile '${item.storyFile}' in the Storybook index`,\n );\n }\n }\n\n return resolved;\n}\n\nfunction normalizeImportPath(p: string): string {\n return p.startsWith('./') ? p.slice(2) : p;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["fs", "path", "path", "HAPPO_DEBUG", "fs", "path"]
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/storybook/preset.ts"],"names":[],"mappings":"AAKA,wBAAgB,cAAc,CAAC,KAAK,GAAE,KAAK,CAAC,MAAM,CAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAEvE;AAED,wBAAgB,MAAM,CAAC,KAAK,GAAE,KAAK,CAAC,MAAM,CAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAE/D"}
1
+ {"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/storybook/preset.ts"],"names":[],"mappings":"AAOA,wBAAgB,cAAc,CAAC,KAAK,GAAE,KAAK,CAAC,MAAM,CAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAOvE;AAED,wBAAgB,MAAM,CAAC,KAAK,GAAE,KAAK,CAAC,MAAM,CAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAE/D"}