storybook 10.1.0-alpha.10 → 10.1.0-alpha.11
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/_browser-chunks/Color-FTG7SQDA.js +1097 -0
- package/dist/_browser-chunks/WithTooltip-LMROHDUP.js +1651 -0
- package/dist/_browser-chunks/chunk-2FRVAXCZ.js +7 -0
- package/dist/_browser-chunks/chunk-3IAH5M2U.js +171 -0
- package/dist/_browser-chunks/chunk-3OXGAGBE.js +779 -0
- package/dist/_browser-chunks/{chunk-TMDZCWME.js → chunk-3PJE6VLG.js} +1 -3
- package/dist/_browser-chunks/{chunk-VAMFPZY3.js → chunk-45UGUKRX.js} +2 -7
- package/dist/_browser-chunks/chunk-6XWLIJQL.js +11 -0
- package/dist/_browser-chunks/{chunk-FDWKXLBI.js → chunk-74YHFU5B.js} +44 -109
- package/dist/_browser-chunks/{chunk-MM7DTO55.js → chunk-A242L54C.js} +10 -16
- package/dist/_browser-chunks/chunk-AIOS4NGK.js +252 -0
- package/dist/_browser-chunks/chunk-AS2HQEYC.js +14 -0
- package/dist/_browser-chunks/chunk-AXG2BOBL.js +836 -0
- package/dist/_browser-chunks/chunk-BE2DAXKJ.js +2966 -0
- package/dist/_browser-chunks/{chunk-MH6AXFXB.js → chunk-CHUV5WSW.js} +0 -5
- package/dist/_browser-chunks/chunk-EBHB6RPS.js +61 -0
- package/dist/_browser-chunks/chunk-EUVGDK4H.js +93 -0
- package/dist/_browser-chunks/chunk-EZSQOHRI.js +18 -0
- package/dist/_browser-chunks/{chunk-CADGRH3P.js → chunk-FNXWN6IK.js} +3 -8
- package/dist/_browser-chunks/chunk-GFLS4VP3.js +64 -0
- package/dist/_browser-chunks/{chunk-L2D73C6Z.js → chunk-H6XK3RSC.js} +13 -21
- package/dist/_browser-chunks/chunk-IPA5A322.js +71 -0
- package/dist/_browser-chunks/chunk-JP7NCOJX.js +37 -0
- package/dist/_browser-chunks/chunk-KJHJLCBK.js +11 -0
- package/dist/_browser-chunks/{chunk-QMY4G4R2.js → chunk-L4RMQ7D7.js} +17 -64
- package/dist/_browser-chunks/{chunk-AB7OOPUX.js → chunk-QKODTO7K.js} +0 -5
- package/dist/_browser-chunks/chunk-RP5RXKFU.js +2491 -0
- package/dist/_browser-chunks/chunk-SL75JR6Y.js +9 -0
- package/dist/_browser-chunks/chunk-UD6FQLAF.js +1481 -0
- package/dist/_browser-chunks/chunk-VYJQ7RU5.js +2853 -0
- package/dist/_browser-chunks/chunk-WJYERY3R.js +136 -0
- package/dist/_browser-chunks/chunk-WXP2XJ3O.js +950 -0
- package/dist/_browser-chunks/chunk-X3DUQ5RA.js +47 -0
- package/dist/_browser-chunks/chunk-XJNX76GA.js +85 -0
- package/dist/_browser-chunks/{chunk-F4Q6SGTB.js → chunk-YKE5S47A.js} +177 -399
- package/dist/_browser-chunks/{chunk-SN4J4IQ3.js → chunk-ZUWEVLDX.js} +1 -7
- package/dist/_browser-chunks/{formatter-OMEEQ6HG.js → formatter-QJ4M4OGQ.js} +4 -9
- package/dist/_browser-chunks/{syntaxhighlighter-RJZASWHL.js → syntaxhighlighter-WKBQ5RC7.js} +704 -1848
- package/dist/_node-chunks/{builder-manager-HA7CYFCK.js → builder-manager-PMPHOSM2.js} +475 -1013
- package/dist/_node-chunks/camelcase-K3IOOFQW.js +18 -0
- package/dist/_node-chunks/{chunk-X4XU27M6.js → chunk-32NE3UE3.js} +15 -24
- package/dist/_node-chunks/chunk-4GZCFQFG.js +58 -0
- package/dist/_node-chunks/chunk-5QK5MSOI.js +943 -0
- package/dist/_node-chunks/{chunk-VPR5IBMG.js → chunk-6ZOLETQK.js} +8 -10
- package/dist/_node-chunks/chunk-7I22Y76Z.js +1047 -0
- package/dist/_node-chunks/chunk-AKTRSR3O.js +72 -0
- package/dist/_node-chunks/chunk-BBOP3XCK.js +119 -0
- package/dist/_node-chunks/chunk-C2GQVDWI.js +34 -0
- package/dist/_node-chunks/{chunk-ZHSCUGNP.js → chunk-GG2WQZSG.js} +3799 -7849
- package/dist/_node-chunks/chunk-GQJOWVVR.js +3214 -0
- package/dist/_node-chunks/chunk-JCRM2YVK.js +3009 -0
- package/dist/_node-chunks/chunk-KK4AT5F3.js +1029 -0
- package/dist/_node-chunks/chunk-L7MYXJUM.js +1114 -0
- package/dist/_node-chunks/{chunk-F3XOPI6H.js → chunk-LCZO45L7.js} +469 -983
- package/dist/_node-chunks/chunk-LR3QITDI.js +209 -0
- package/dist/_node-chunks/chunk-LXG4DK35.js +3171 -0
- package/dist/_node-chunks/chunk-MJ3WOS6F.js +37 -0
- package/dist/_node-chunks/chunk-PHOZWZZO.js +61 -0
- package/dist/_node-chunks/chunk-QECOQWRJ.js +936 -0
- package/dist/_node-chunks/chunk-QH4V5YDB.js +20 -0
- package/dist/_node-chunks/chunk-R6HWGZWD.js +26 -0
- package/dist/_node-chunks/chunk-SPQXMU2Q.js +759 -0
- package/dist/_node-chunks/chunk-TXZY6V6O.js +1564 -0
- package/dist/_node-chunks/chunk-UGDPX5LE.js +756 -0
- package/dist/_node-chunks/chunk-UY26MQLT.js +603 -0
- package/dist/_node-chunks/chunk-WK3EMYK6.js +61 -0
- package/dist/_node-chunks/{chunk-OVXB5GGT.js → chunk-WLHMN7AP.js} +292 -688
- package/dist/_node-chunks/chunk-XGVLB4UJ.js +54 -0
- package/dist/_node-chunks/{chunk-RMHAL25C.js → chunk-YHRFI6BE.js} +87 -227
- package/dist/_node-chunks/chunk-YK4KVMFW.js +18 -0
- package/dist/_node-chunks/chunk-ZZALGOA6.js +4523 -0
- package/dist/_node-chunks/chunk-ZZPBSYA5.js +301 -0
- package/dist/_node-chunks/chunk-ZZSRFAC6.js +45571 -0
- package/dist/_node-chunks/dist-4DWOCZUD.js +121 -0
- package/dist/_node-chunks/globby-AAARUKEU.js +3452 -0
- package/dist/_node-chunks/lib-HEUKGL62.js +366 -0
- package/dist/_node-chunks/mdx-N42X6CFJ-DCVRPS6N.js +14329 -0
- package/dist/_node-chunks/p-limit-F5ZKJ6WZ.js +116 -0
- package/dist/_node-chunks/plugin-7YY7JXCH.js +123 -0
- package/dist/_node-chunks/{plugin-6ZPCS4LI.js → plugin-SZP3CW6W.js} +36 -56
- package/dist/_node-chunks/webpack-inject-mocker-runtime-plugin-TGKNDPO6.js +46623 -0
- package/dist/_node-chunks/webpack-mock-plugin-LNTZZFBE.js +92 -0
- package/dist/actions/decorator.js +21 -42
- package/dist/actions/index.js +3 -3
- package/dist/babel/index.d.ts +671 -335
- package/dist/babel/index.js +11 -11
- package/dist/bin/core.js +592 -1546
- package/dist/bin/dispatcher.js +26 -37
- package/dist/bin/loader.js +23 -34
- package/dist/channels/index.js +98 -234
- package/dist/cli/index.js +1951 -5308
- package/dist/client-logger/index.js +31 -61
- package/dist/common/index.js +20 -20
- package/dist/components/index.js +4211 -8586
- package/dist/core-events/index.js +2 -66
- package/dist/core-server/index.js +3054 -7290
- package/dist/core-server/presets/common-manager.css +2 -2
- package/dist/core-server/presets/common-manager.js +1806 -3427
- package/dist/core-server/presets/common-override-preset.js +31 -60
- package/dist/core-server/presets/common-preset.js +434 -924
- package/dist/core-server/presets/webpack/loaders/storybook-mock-transform-loader.js +15 -19
- package/dist/core-server/presets/webpack/loaders/webpack-automock-loader.js +12 -17
- package/dist/csf/index.js +534 -1179
- package/dist/csf-tools/index.js +9 -9
- package/dist/docs-tools/index.js +6 -6
- package/dist/highlight/index.js +2 -2
- package/dist/instrumenter/index.js +199 -415
- package/dist/manager/globals-runtime.js +24150 -47364
- package/dist/manager/globals.js +2 -3
- package/dist/manager/runtime.js +3961 -8373
- package/dist/manager-api/index.js +1231 -2425
- package/dist/manager-errors.d.ts +3 -0
- package/dist/manager-errors.js +3 -3
- package/dist/node-logger/index.js +1253 -2601
- package/dist/preview/globals.js +2 -3
- package/dist/preview/runtime.js +10364 -21990
- package/dist/preview-api/index.d.ts +67 -68
- package/dist/preview-api/index.js +13 -13
- package/dist/preview-errors.d.ts +3 -0
- package/dist/preview-errors.js +4 -4
- package/dist/router/index.js +347 -899
- package/dist/server-errors.d.ts +3 -0
- package/dist/server-errors.js +10 -10
- package/dist/telemetry/index.js +24 -24
- package/dist/test/index.js +5860 -11645
- package/dist/theming/create.js +4 -4
- package/dist/theming/index.d.ts +3363 -2597
- package/dist/theming/index.js +490 -1086
- package/dist/types/index.js +2 -11
- package/dist/viewport/index.js +3 -3
- package/package.json +5 -5
- package/dist/_browser-chunks/Color-FQNEU7YS.js +0 -1695
- package/dist/_browser-chunks/WithTooltip-6NHN2GXF.js +0 -2343
- package/dist/_browser-chunks/chunk-6A7OIVEL.js +0 -66
- package/dist/_browser-chunks/chunk-AW46NMGV.js +0 -1308
- package/dist/_browser-chunks/chunk-B4A3ADP3.js +0 -3816
- package/dist/_browser-chunks/chunk-FSBVR7H5.js +0 -106
- package/dist/_browser-chunks/chunk-FUOHXXZT.js +0 -23
- package/dist/_browser-chunks/chunk-GTKOCWCT.js +0 -17
- package/dist/_browser-chunks/chunk-HHW4FUMO.js +0 -12
- package/dist/_browser-chunks/chunk-JVSKG4YS.js +0 -4052
- package/dist/_browser-chunks/chunk-LASUB7TL.js +0 -76
- package/dist/_browser-chunks/chunk-LYCSRYYR.js +0 -101
- package/dist/_browser-chunks/chunk-NVV6MIOE.js +0 -243
- package/dist/_browser-chunks/chunk-OBXWFEPB.js +0 -852
- package/dist/_browser-chunks/chunk-OPCDBBL3.js +0 -48
- package/dist/_browser-chunks/chunk-PB6FZ3WE.js +0 -130
- package/dist/_browser-chunks/chunk-RW5PKMWM.js +0 -4182
- package/dist/_browser-chunks/chunk-SYS437NN.js +0 -122
- package/dist/_browser-chunks/chunk-U46RQHA4.js +0 -12
- package/dist/_browser-chunks/chunk-UTNZYD2N.js +0 -311
- package/dist/_browser-chunks/chunk-VUAFL5XK.js +0 -20
- package/dist/_browser-chunks/chunk-XDGMHOV7.js +0 -2197
- package/dist/_browser-chunks/chunk-XW6KSYKF.js +0 -16
- package/dist/_browser-chunks/chunk-Y3M7TW6K.js +0 -1041
- package/dist/_browser-chunks/chunk-ZNRFDIVA.js +0 -233
- package/dist/_node-chunks/camelcase-QALD4XFE.js +0 -18
- package/dist/_node-chunks/chunk-2XY53ALL.js +0 -420
- package/dist/_node-chunks/chunk-3CBQMG2A.js +0 -6712
- package/dist/_node-chunks/chunk-3WDAPZYQ.js +0 -28
- package/dist/_node-chunks/chunk-4ZB555EJ.js +0 -697
- package/dist/_node-chunks/chunk-52DXKXY3.js +0 -4272
- package/dist/_node-chunks/chunk-5OVB4A6F.js +0 -69
- package/dist/_node-chunks/chunk-AGHGNXGH.js +0 -18
- package/dist/_node-chunks/chunk-B23X5ZCK.js +0 -1531
- package/dist/_node-chunks/chunk-B2DAHWJK.js +0 -220
- package/dist/_node-chunks/chunk-CC4PW5MJ.js +0 -34
- package/dist/_node-chunks/chunk-D7NIZELR.js +0 -2256
- package/dist/_node-chunks/chunk-DO5Q3H4L.js +0 -1250
- package/dist/_node-chunks/chunk-ECK7WVFX.js +0 -304
- package/dist/_node-chunks/chunk-EUH3NHXA.js +0 -79
- package/dist/_node-chunks/chunk-FOQHPHCV.js +0 -1657
- package/dist/_node-chunks/chunk-G6EL47NS.js +0 -111
- package/dist/_node-chunks/chunk-GFLS4TJB.js +0 -90
- package/dist/_node-chunks/chunk-J3XZKWHE.js +0 -1586
- package/dist/_node-chunks/chunk-LE63EHJ5.js +0 -1518
- package/dist/_node-chunks/chunk-M47XA42S.js +0 -4741
- package/dist/_node-chunks/chunk-OOI74AL3.js +0 -61
- package/dist/_node-chunks/chunk-PRJHT3GJ.js +0 -61
- package/dist/_node-chunks/chunk-Q52PVUSU.js +0 -101
- package/dist/_node-chunks/chunk-SDCF5RNN.js +0 -1198
- package/dist/_node-chunks/chunk-UJ5SJ23M.js +0 -5029
- package/dist/_node-chunks/chunk-UPHK4ETU.js +0 -64658
- package/dist/_node-chunks/chunk-V7VURIPB.js +0 -1544
- package/dist/_node-chunks/dist-6TXHNR5C.js +0 -175
- package/dist/_node-chunks/globby-PBTV6PX6.js +0 -5222
- package/dist/_node-chunks/lib-4RTDZVGX.js +0 -518
- package/dist/_node-chunks/mdx-N42X6CFJ-COWEH7KR.js +0 -22017
- package/dist/_node-chunks/p-limit-PBVZQOFY.js +0 -168
- package/dist/_node-chunks/plugin-EOZKYZAG.js +0 -159
- package/dist/_node-chunks/webpack-inject-mocker-runtime-plugin-35HMSMR5.js +0 -69102
- package/dist/_node-chunks/webpack-mock-plugin-GT3MA5E2.js +0 -124
|
@@ -0,0 +1,1564 @@
|
|
|
1
|
+
import CJS_COMPAT_NODE_URL_843v2rliy1 from 'node:url';
|
|
2
|
+
import CJS_COMPAT_NODE_PATH_843v2rliy1 from 'node:path';
|
|
3
|
+
import CJS_COMPAT_NODE_MODULE_843v2rliy1 from "node:module";
|
|
4
|
+
|
|
5
|
+
var __filename = CJS_COMPAT_NODE_URL_843v2rliy1.fileURLToPath(import.meta.url);
|
|
6
|
+
var __dirname = CJS_COMPAT_NODE_PATH_843v2rliy1.dirname(__filename);
|
|
7
|
+
var require = CJS_COMPAT_NODE_MODULE_843v2rliy1.createRequire(import.meta.url);
|
|
8
|
+
|
|
9
|
+
// ------------------------------------------------------------
|
|
10
|
+
// end of CJS compatibility banner, injected by Storybook's esbuild configuration
|
|
11
|
+
// ------------------------------------------------------------
|
|
12
|
+
import {
|
|
13
|
+
require_dist
|
|
14
|
+
} from "./chunk-PHOZWZZO.js";
|
|
15
|
+
import {
|
|
16
|
+
__toESM
|
|
17
|
+
} from "./chunk-XGVLB4UJ.js";
|
|
18
|
+
|
|
19
|
+
// src/csf-tools/CsfFile.ts
|
|
20
|
+
var import_ts_dedent = __toESM(require_dist(), 1);
|
|
21
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
22
|
+
import {
|
|
23
|
+
BabelFileClass,
|
|
24
|
+
babelParse,
|
|
25
|
+
generate,
|
|
26
|
+
recast,
|
|
27
|
+
types as t2,
|
|
28
|
+
traverse
|
|
29
|
+
} from "storybook/internal/babel";
|
|
30
|
+
import { isExportStory, storyNameFromExport, toId, toTestId } from "storybook/internal/csf";
|
|
31
|
+
import { logger } from "storybook/internal/node-logger";
|
|
32
|
+
|
|
33
|
+
// src/csf-tools/findVarInitialization.ts
|
|
34
|
+
import { types as t } from "storybook/internal/babel";
|
|
35
|
+
var findVarInitialization = (identifier, program) => {
|
|
36
|
+
let init = null, declarations = null;
|
|
37
|
+
return program.body.find((node) => (t.isVariableDeclaration(node) ? declarations = node.declarations : t.isExportNamedDeclaration(node) && t.isVariableDeclaration(node.declaration) && (declarations = node.declaration.declarations), declarations && declarations.find((decl) => t.isVariableDeclarator(decl) && t.isIdentifier(decl.id) && decl.id.name === identifier ? (init = decl.init, !0) : !1))), init;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// src/csf-tools/CsfFile.ts
|
|
41
|
+
var PREVIEW_FILE_REGEX = /\/preview(.(js|jsx|mjs|ts|tsx))?$/, isValidPreviewPath = (filepath) => PREVIEW_FILE_REGEX.test(filepath);
|
|
42
|
+
function parseIncludeExclude(prop) {
|
|
43
|
+
if (t2.isArrayExpression(prop))
|
|
44
|
+
return prop.elements.map((e) => {
|
|
45
|
+
if (t2.isStringLiteral(e))
|
|
46
|
+
return e.value;
|
|
47
|
+
throw new Error(`Expected string literal: ${e}`);
|
|
48
|
+
});
|
|
49
|
+
if (t2.isStringLiteral(prop))
|
|
50
|
+
return new RegExp(prop.value);
|
|
51
|
+
if (t2.isRegExpLiteral(prop))
|
|
52
|
+
return new RegExp(prop.pattern, prop.flags);
|
|
53
|
+
throw new Error(`Unknown include/exclude: ${prop}`);
|
|
54
|
+
}
|
|
55
|
+
function parseTags(prop) {
|
|
56
|
+
if (!t2.isArrayExpression(prop))
|
|
57
|
+
throw new Error("CSF: Expected tags array");
|
|
58
|
+
return prop.elements.map((e) => {
|
|
59
|
+
if (t2.isStringLiteral(e))
|
|
60
|
+
return e.value;
|
|
61
|
+
throw new Error("CSF: Expected tag to be string literal");
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function parseTestTags(optionsNode, program) {
|
|
65
|
+
if (!optionsNode)
|
|
66
|
+
return [];
|
|
67
|
+
let node = optionsNode;
|
|
68
|
+
if (t2.isIdentifier(node) && (node = findVarInitialization(node.name, program)), t2.isObjectExpression(node)) {
|
|
69
|
+
let tagsProp = node.properties.find(
|
|
70
|
+
(property) => t2.isObjectProperty(property) && t2.isIdentifier(property.key) && property.key.name === "tags"
|
|
71
|
+
);
|
|
72
|
+
if (tagsProp) {
|
|
73
|
+
let tagsNode = tagsProp.value;
|
|
74
|
+
return t2.isIdentifier(tagsNode) && (tagsNode = findVarInitialization(tagsNode.name, program)), parseTags(tagsNode);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
var formatLocation = (node, fileName) => {
|
|
80
|
+
let loc = "";
|
|
81
|
+
if (node.loc) {
|
|
82
|
+
let { line, column } = node.loc?.start || {};
|
|
83
|
+
loc = `(line ${line}, col ${column})`;
|
|
84
|
+
}
|
|
85
|
+
return `${fileName || ""} ${loc}`.trim();
|
|
86
|
+
}, isModuleMock = (importPath) => MODULE_MOCK_REGEX.test(importPath), isArgsStory = (init, parent, csf) => {
|
|
87
|
+
let storyFn = init;
|
|
88
|
+
if (t2.isCallExpression(init)) {
|
|
89
|
+
let { callee, arguments: bindArguments } = init;
|
|
90
|
+
if (t2.isProgram(parent) && t2.isMemberExpression(callee) && t2.isIdentifier(callee.object) && t2.isIdentifier(callee.property) && callee.property.name === "bind" && (bindArguments.length === 0 || bindArguments.length === 1 && t2.isObjectExpression(bindArguments[0]) && bindArguments[0].properties.length === 0)) {
|
|
91
|
+
let boundIdentifier = callee.object.name, template = findVarInitialization(boundIdentifier, parent);
|
|
92
|
+
template && (csf._templates[boundIdentifier] = template, storyFn = template);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return t2.isArrowFunctionExpression(storyFn) || t2.isFunctionDeclaration(storyFn) ? storyFn.params.length > 0 : !1;
|
|
96
|
+
}, parseExportsOrder = (init) => {
|
|
97
|
+
if (t2.isArrayExpression(init))
|
|
98
|
+
return init.elements.map((item) => {
|
|
99
|
+
if (t2.isStringLiteral(item))
|
|
100
|
+
return item.value;
|
|
101
|
+
throw new Error(`Expected string literal named export: ${item}`);
|
|
102
|
+
});
|
|
103
|
+
throw new Error(`Expected array of string literals: ${init}`);
|
|
104
|
+
}, sortExports = (exportByName, order) => order.reduce(
|
|
105
|
+
(acc, name) => {
|
|
106
|
+
let namedExport = exportByName[name];
|
|
107
|
+
return namedExport && (acc[name] = namedExport), acc;
|
|
108
|
+
},
|
|
109
|
+
{}
|
|
110
|
+
), hasMount = (play) => {
|
|
111
|
+
if (t2.isArrowFunctionExpression(play) || t2.isFunctionDeclaration(play) || t2.isObjectMethod(play)) {
|
|
112
|
+
let params = play.params;
|
|
113
|
+
if (params.length >= 1) {
|
|
114
|
+
let [arg] = params;
|
|
115
|
+
if (t2.isObjectPattern(arg))
|
|
116
|
+
return !!arg.properties.find((prop) => {
|
|
117
|
+
if (t2.isObjectProperty(prop) && t2.isIdentifier(prop.key))
|
|
118
|
+
return prop.key.name === "mount";
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return !1;
|
|
123
|
+
}, MODULE_MOCK_REGEX = /^[.\/#].*\.mock($|\.[^.]*$)/i, NoMetaError = class extends Error {
|
|
124
|
+
constructor(message, ast, fileName) {
|
|
125
|
+
let msg = message.trim();
|
|
126
|
+
super(import_ts_dedent.dedent`
|
|
127
|
+
CSF: ${msg} ${formatLocation(ast, fileName)}
|
|
128
|
+
|
|
129
|
+
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export
|
|
130
|
+
`), this.name = this.constructor.name;
|
|
131
|
+
}
|
|
132
|
+
}, MultipleMetaError = class extends Error {
|
|
133
|
+
constructor(message, ast, fileName) {
|
|
134
|
+
let msg = `${message} ${formatLocation(ast, fileName)}`.trim();
|
|
135
|
+
super(import_ts_dedent.dedent`
|
|
136
|
+
CSF: ${message} ${formatLocation(ast, fileName)}
|
|
137
|
+
|
|
138
|
+
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export
|
|
139
|
+
`), this.name = this.constructor.name;
|
|
140
|
+
}
|
|
141
|
+
}, MixedFactoryError = class extends Error {
|
|
142
|
+
constructor(message, ast, fileName) {
|
|
143
|
+
let msg = `${message} ${formatLocation(ast, fileName)}`.trim();
|
|
144
|
+
super(import_ts_dedent.dedent`
|
|
145
|
+
CSF: ${message} ${formatLocation(ast, fileName)}
|
|
146
|
+
|
|
147
|
+
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export
|
|
148
|
+
`), this.name = this.constructor.name;
|
|
149
|
+
}
|
|
150
|
+
}, BadMetaError = class extends Error {
|
|
151
|
+
constructor(message, ast, fileName) {
|
|
152
|
+
let msg = "".trim();
|
|
153
|
+
super(import_ts_dedent.dedent`
|
|
154
|
+
CSF: ${message} ${formatLocation(ast, fileName)}
|
|
155
|
+
|
|
156
|
+
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export
|
|
157
|
+
`), this.name = this.constructor.name;
|
|
158
|
+
}
|
|
159
|
+
}, CsfFile = class {
|
|
160
|
+
constructor(ast, options, file) {
|
|
161
|
+
this._stories = {};
|
|
162
|
+
this._metaAnnotations = {};
|
|
163
|
+
this._storyExports = {};
|
|
164
|
+
this._storyDeclarationPath = {};
|
|
165
|
+
this._storyPaths = {};
|
|
166
|
+
this._storyStatements = {};
|
|
167
|
+
this._storyAnnotations = {};
|
|
168
|
+
this._templates = {};
|
|
169
|
+
this._tests = [];
|
|
170
|
+
this._ast = ast, this._file = file, this._options = options, this.imports = [];
|
|
171
|
+
}
|
|
172
|
+
_parseTitle(value) {
|
|
173
|
+
let node = t2.isIdentifier(value) ? findVarInitialization(value.name, this._ast.program) : value;
|
|
174
|
+
if (t2.isStringLiteral(node))
|
|
175
|
+
return node.value;
|
|
176
|
+
if (t2.isTSSatisfiesExpression(node) && t2.isStringLiteral(node.expression))
|
|
177
|
+
return node.expression.value;
|
|
178
|
+
throw new Error(import_ts_dedent.dedent`
|
|
179
|
+
CSF: unexpected dynamic title ${formatLocation(node, this._options.fileName)}
|
|
180
|
+
|
|
181
|
+
More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#string-literal-titles
|
|
182
|
+
`);
|
|
183
|
+
}
|
|
184
|
+
_parseMeta(declaration, program) {
|
|
185
|
+
if (this._metaNode)
|
|
186
|
+
throw new MultipleMetaError("multiple meta objects", declaration, this._options.fileName);
|
|
187
|
+
this._metaNode = declaration;
|
|
188
|
+
let meta = {};
|
|
189
|
+
declaration.properties.forEach((p) => {
|
|
190
|
+
if (t2.isIdentifier(p.key)) {
|
|
191
|
+
let value = t2.isObjectMethod(p) ? p : p.value;
|
|
192
|
+
if (this._metaAnnotations[p.key.name] = value, p.key.name === "title")
|
|
193
|
+
meta.title = this._parseTitle(p.value);
|
|
194
|
+
else if (["includeStories", "excludeStories"].includes(p.key.name))
|
|
195
|
+
meta[p.key.name] = parseIncludeExclude(p.value);
|
|
196
|
+
else if (p.key.name === "component") {
|
|
197
|
+
let n = p.value;
|
|
198
|
+
if (t2.isIdentifier(n)) {
|
|
199
|
+
let id = n.name, importStmt = program.body.find(
|
|
200
|
+
(stmt) => t2.isImportDeclaration(stmt) && stmt.specifiers.find((spec) => spec.local.name === id)
|
|
201
|
+
);
|
|
202
|
+
if (importStmt) {
|
|
203
|
+
let { source } = importStmt, specifier = importStmt.specifiers.find((spec) => spec.local.name === id);
|
|
204
|
+
t2.isStringLiteral(source) && specifier && (this._rawComponentPath = source.value, (t2.isImportSpecifier(specifier) || t2.isImportDefaultSpecifier(specifier)) && (this._componentImportSpecifier = specifier));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
let { code } = recast.print(p.value, {});
|
|
208
|
+
meta.component = code;
|
|
209
|
+
} else if (p.key.name === "tags") {
|
|
210
|
+
let node = p.value;
|
|
211
|
+
t2.isIdentifier(node) && (node = findVarInitialization(node.name, this._ast.program)), meta.tags = parseTags(node);
|
|
212
|
+
} else if (p.key.name === "id")
|
|
213
|
+
if (t2.isStringLiteral(p.value))
|
|
214
|
+
meta.id = p.value.value;
|
|
215
|
+
else
|
|
216
|
+
throw new Error(`Unexpected component id: ${p.value}`);
|
|
217
|
+
}
|
|
218
|
+
}), this._meta = meta;
|
|
219
|
+
}
|
|
220
|
+
getStoryExport(key) {
|
|
221
|
+
let node = this._storyExports[key];
|
|
222
|
+
if (node = t2.isVariableDeclarator(node) ? node.init : node, t2.isCallExpression(node)) {
|
|
223
|
+
let { callee, arguments: bindArguments } = node;
|
|
224
|
+
if (t2.isMemberExpression(callee) && t2.isIdentifier(callee.object) && t2.isIdentifier(callee.property) && callee.property.name === "bind" && (bindArguments.length === 0 || bindArguments.length === 1 && t2.isObjectExpression(bindArguments[0]) && bindArguments[0].properties.length === 0)) {
|
|
225
|
+
let { name } = callee.object;
|
|
226
|
+
node = this._templates[name];
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return node;
|
|
230
|
+
}
|
|
231
|
+
parse() {
|
|
232
|
+
let self = this;
|
|
233
|
+
if (traverse(this._ast, {
|
|
234
|
+
ExportDefaultDeclaration: {
|
|
235
|
+
enter(path) {
|
|
236
|
+
let { node, parent } = path, isVariableReference = t2.isIdentifier(node.declaration) && t2.isProgram(parent);
|
|
237
|
+
if (self._options.transformInlineMeta && !isVariableReference && t2.isExpression(node.declaration)) {
|
|
238
|
+
let metaId = path.scope.generateUidIdentifier("meta");
|
|
239
|
+
self._metaVariableName = metaId.name;
|
|
240
|
+
let nodes = [
|
|
241
|
+
t2.variableDeclaration("const", [t2.variableDeclarator(metaId, node.declaration)]),
|
|
242
|
+
t2.exportDefaultDeclaration(metaId)
|
|
243
|
+
];
|
|
244
|
+
nodes.forEach((_node) => _node.loc = path.node.loc), path.replaceWithMultiple(nodes);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
let metaNode, decl;
|
|
248
|
+
if (isVariableReference) {
|
|
249
|
+
let variableName = node.declaration.name;
|
|
250
|
+
self._metaVariableName = variableName;
|
|
251
|
+
let isMetaVariable = (declaration) => t2.isIdentifier(declaration.id) && declaration.id.name === variableName;
|
|
252
|
+
self._metaStatementPath = self._file.path.get("body").find(
|
|
253
|
+
(path2) => path2.isVariableDeclaration() && path2.node.declarations.some(isMetaVariable)
|
|
254
|
+
), self._metaStatement = self._metaStatementPath?.node, decl = (self?._metaStatement?.declarations || []).find(
|
|
255
|
+
isMetaVariable
|
|
256
|
+
)?.init;
|
|
257
|
+
} else
|
|
258
|
+
self._metaStatement = node, self._metaStatementPath = path, decl = node.declaration;
|
|
259
|
+
if (t2.isObjectExpression(decl) ? metaNode = decl : /* export default { ... } as Meta<...> */ /* export default { ... } satisfies Meta<...> */ (t2.isTSAsExpression(decl) || t2.isTSSatisfiesExpression(decl)) && t2.isObjectExpression(decl.expression) ? metaNode = decl.expression : (
|
|
260
|
+
// export default { ... } satisfies Meta as Meta<...>
|
|
261
|
+
t2.isTSAsExpression(decl) && t2.isTSSatisfiesExpression(decl.expression) && t2.isObjectExpression(decl.expression.expression) && (metaNode = decl.expression.expression)
|
|
262
|
+
), metaNode && t2.isProgram(parent) && self._parseMeta(metaNode, parent), self._metaStatement && !self._metaNode)
|
|
263
|
+
throw new NoMetaError(
|
|
264
|
+
"default export must be an object",
|
|
265
|
+
self._metaStatement,
|
|
266
|
+
self._options.fileName
|
|
267
|
+
);
|
|
268
|
+
self._metaPath = path;
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
ExportNamedDeclaration: {
|
|
272
|
+
enter(path) {
|
|
273
|
+
let { node, parent } = path, declaration = path.get("declaration"), declarations;
|
|
274
|
+
declaration.isVariableDeclaration() ? declarations = declaration.get("declarations").filter((d) => d.isVariableDeclarator()) : declaration.isFunctionDeclaration() && (declarations = [declaration]), declarations ? declarations.forEach((declPath) => {
|
|
275
|
+
let decl = declPath.node, id = declPath.node.id;
|
|
276
|
+
if (t2.isIdentifier(id)) {
|
|
277
|
+
let storyIsFactory = !1, { name: exportName } = id;
|
|
278
|
+
if (exportName === "__namedExportsOrder" && declPath.isVariableDeclarator()) {
|
|
279
|
+
self._namedExportsOrder = parseExportsOrder(declPath.node.init);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
self._storyExports[exportName] = decl, self._storyDeclarationPath[exportName] = declPath, self._storyPaths[exportName] = path, self._storyStatements[exportName] = node;
|
|
283
|
+
let name = storyNameFromExport(exportName);
|
|
284
|
+
self._storyAnnotations[exportName] ? logger.warn(
|
|
285
|
+
`Unexpected annotations for "${exportName}" before story declaration`
|
|
286
|
+
) : self._storyAnnotations[exportName] = {};
|
|
287
|
+
let storyNode;
|
|
288
|
+
if (t2.isVariableDeclarator(decl) ? t2.isTSAsExpression(decl.init) && t2.isTSSatisfiesExpression(decl.init.expression) ? storyNode = decl.init.expression.expression : t2.isTSAsExpression(decl.init) || t2.isTSSatisfiesExpression(decl.init) ? storyNode = decl.init.expression : storyNode = decl.init : storyNode = decl, t2.isCallExpression(storyNode) && t2.isMemberExpression(storyNode.callee) && t2.isIdentifier(storyNode.callee.property) && (storyNode.callee.property.name === "story" || storyNode.callee.property.name === "extend") && (storyIsFactory = !0, storyNode = storyNode.arguments[0]), self._metaIsFactory && !storyIsFactory)
|
|
289
|
+
throw new MixedFactoryError(
|
|
290
|
+
"expected factory story",
|
|
291
|
+
storyNode,
|
|
292
|
+
self._options.fileName
|
|
293
|
+
);
|
|
294
|
+
if (!self._metaIsFactory && storyIsFactory)
|
|
295
|
+
throw self._metaNode ? new MixedFactoryError(
|
|
296
|
+
"expected non-factory story",
|
|
297
|
+
storyNode,
|
|
298
|
+
self._options.fileName
|
|
299
|
+
) : new BadMetaError(
|
|
300
|
+
"meta() factory must be imported from .storybook/preview configuration",
|
|
301
|
+
storyNode,
|
|
302
|
+
self._options.fileName
|
|
303
|
+
);
|
|
304
|
+
let parameters = {};
|
|
305
|
+
t2.isObjectExpression(storyNode) ? (parameters.__isArgsStory = !0, storyNode.properties.forEach((p) => {
|
|
306
|
+
if (t2.isIdentifier(p.key)) {
|
|
307
|
+
let key = p.key.name;
|
|
308
|
+
if (t2.isObjectMethod(p))
|
|
309
|
+
self._storyAnnotations[exportName][key] = p;
|
|
310
|
+
else {
|
|
311
|
+
if (p.key.name === "render")
|
|
312
|
+
parameters.__isArgsStory = isArgsStory(
|
|
313
|
+
p.value,
|
|
314
|
+
parent,
|
|
315
|
+
self
|
|
316
|
+
);
|
|
317
|
+
else if (p.key.name === "name" && t2.isStringLiteral(p.value))
|
|
318
|
+
name = p.value.value;
|
|
319
|
+
else if (p.key.name === "storyName" && t2.isStringLiteral(p.value))
|
|
320
|
+
logger.warn(
|
|
321
|
+
`Unexpected usage of "storyName" in "${exportName}". Please use "name" instead.`
|
|
322
|
+
);
|
|
323
|
+
else if (p.key.name === "parameters" && t2.isObjectExpression(p.value)) {
|
|
324
|
+
let idProperty = p.value.properties.find(
|
|
325
|
+
(property) => t2.isObjectProperty(property) && t2.isIdentifier(property.key) && property.key.name === "__id"
|
|
326
|
+
);
|
|
327
|
+
idProperty && (parameters.__id = idProperty.value.value);
|
|
328
|
+
}
|
|
329
|
+
self._storyAnnotations[exportName][p.key.name] = p.value;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
})) : parameters.__isArgsStory = isArgsStory(storyNode, parent, self), self._stories[exportName] = {
|
|
333
|
+
id: "FIXME",
|
|
334
|
+
name,
|
|
335
|
+
parameters,
|
|
336
|
+
__stats: {
|
|
337
|
+
factory: storyIsFactory
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
}) : node.specifiers.length > 0 && node.specifiers.forEach((specifier) => {
|
|
342
|
+
if (t2.isExportSpecifier(specifier) && t2.isIdentifier(specifier.exported)) {
|
|
343
|
+
let { name: exportName } = specifier.exported, { name: localName } = specifier.local, decl = t2.isProgram(parent) ? findVarInitialization(localName, parent) : specifier.local;
|
|
344
|
+
if (exportName === "default") {
|
|
345
|
+
let metaNode;
|
|
346
|
+
t2.isObjectExpression(decl) ? metaNode = decl : /* export default { ... } as Meta<...> */ /* export default { ... } satisfies Meta<...> */ (t2.isTSAsExpression(decl) || t2.isTSSatisfiesExpression(decl)) && t2.isObjectExpression(decl.expression) ? metaNode = decl.expression : (
|
|
347
|
+
// export default { ... } satisfies Meta as Meta<...>
|
|
348
|
+
t2.isTSAsExpression(decl) && t2.isTSSatisfiesExpression(decl.expression) && t2.isObjectExpression(decl.expression.expression) && (metaNode = decl.expression.expression)
|
|
349
|
+
), metaNode && t2.isProgram(parent) && self._parseMeta(metaNode, parent);
|
|
350
|
+
} else {
|
|
351
|
+
let annotations = {}, storyNode = decl;
|
|
352
|
+
t2.isObjectExpression(storyNode) && storyNode.properties.forEach((p) => {
|
|
353
|
+
t2.isIdentifier(p.key) && (annotations[p.key.name] = p.value);
|
|
354
|
+
}), self._storyAnnotations[exportName] = annotations, self._storyStatements[exportName] = decl, self._storyPaths[exportName] = path, self._stories[exportName] = {
|
|
355
|
+
id: "FIXME",
|
|
356
|
+
name: exportName,
|
|
357
|
+
localName,
|
|
358
|
+
parameters: {},
|
|
359
|
+
__stats: {}
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
ExpressionStatement: {
|
|
367
|
+
enter({ node, parent }) {
|
|
368
|
+
let { expression } = node;
|
|
369
|
+
if (t2.isProgram(parent) && t2.isAssignmentExpression(expression) && t2.isMemberExpression(expression.left) && t2.isIdentifier(expression.left.object) && t2.isIdentifier(expression.left.property)) {
|
|
370
|
+
let exportName = expression.left.object.name, annotationKey = expression.left.property.name, annotationValue = expression.right;
|
|
371
|
+
if (self._storyAnnotations[exportName] && (annotationKey === "story" && t2.isObjectExpression(annotationValue) ? annotationValue.properties.forEach((prop) => {
|
|
372
|
+
t2.isIdentifier(prop.key) && (self._storyAnnotations[exportName][prop.key.name] = prop.value);
|
|
373
|
+
}) : self._storyAnnotations[exportName][annotationKey] = annotationValue), annotationKey === "storyName" && t2.isStringLiteral(annotationValue)) {
|
|
374
|
+
let storyName = annotationValue.value, story = self._stories[exportName];
|
|
375
|
+
if (!story)
|
|
376
|
+
return;
|
|
377
|
+
story.name = storyName;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (t2.isCallExpression(expression) && t2.isMemberExpression(expression.callee) && t2.isIdentifier(expression.callee.object) && t2.isIdentifier(expression.callee.property) && expression.callee.property.name === "test" && expression.arguments.length >= 2 && t2.isStringLiteral(expression.arguments[0])) {
|
|
381
|
+
let exportName = expression.callee.object.name, testName = expression.arguments[0].value, testFunction = expression.arguments.length === 2 ? expression.arguments[1] : expression.arguments[2], testArguments = expression.arguments.length === 2 ? null : expression.arguments[1], tags = parseTestTags(testArguments, self._ast.program);
|
|
382
|
+
self._tests.push({
|
|
383
|
+
function: testFunction,
|
|
384
|
+
name: testName,
|
|
385
|
+
node: expression,
|
|
386
|
+
// can't set id because meta title isn't available yet
|
|
387
|
+
// so it's set later on
|
|
388
|
+
id: "FIXME",
|
|
389
|
+
tags,
|
|
390
|
+
parent: { node: self._storyStatements[exportName] }
|
|
391
|
+
}), self._stories[exportName].__stats.tests = !0;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
CallExpression: {
|
|
396
|
+
enter(path) {
|
|
397
|
+
let { node } = path, { callee } = node;
|
|
398
|
+
if (t2.isIdentifier(callee) && callee.name === "storiesOf")
|
|
399
|
+
throw new Error(import_ts_dedent.dedent`
|
|
400
|
+
Unexpected \`storiesOf\` usage: ${formatLocation(node, self._options.fileName)}.
|
|
401
|
+
|
|
402
|
+
SB8 does not support \`storiesOf\`.
|
|
403
|
+
`);
|
|
404
|
+
if (t2.isMemberExpression(callee) && t2.isIdentifier(callee.property) && callee.property.name === "meta" && t2.isIdentifier(callee.object) && node.arguments.length > 0) {
|
|
405
|
+
let configParent = path.scope.getBinding(callee.object.name)?.path?.parentPath?.node;
|
|
406
|
+
if (t2.isImportDeclaration(configParent))
|
|
407
|
+
if (isValidPreviewPath(configParent.source.value)) {
|
|
408
|
+
self._metaIsFactory = !0;
|
|
409
|
+
let metaDeclarator = path.findParent(
|
|
410
|
+
(p) => p.isVariableDeclarator()
|
|
411
|
+
);
|
|
412
|
+
self._metaVariableName = t2.isIdentifier(metaDeclarator.node.id) ? metaDeclarator.node.id.name : callee.property.name;
|
|
413
|
+
let metaNode = node.arguments[0];
|
|
414
|
+
self._parseMeta(metaNode, self._ast.program);
|
|
415
|
+
} else
|
|
416
|
+
throw new BadMetaError(
|
|
417
|
+
"meta() factory must be imported from .storybook/preview configuration",
|
|
418
|
+
configParent,
|
|
419
|
+
self._options.fileName
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
ImportDeclaration: {
|
|
425
|
+
enter({ node }) {
|
|
426
|
+
let { source } = node;
|
|
427
|
+
if (t2.isStringLiteral(source))
|
|
428
|
+
self.imports.push(source.value);
|
|
429
|
+
else
|
|
430
|
+
throw new Error("CSF: unexpected import source");
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}), !self._meta)
|
|
434
|
+
throw new NoMetaError("missing default export", self._ast, self._options.fileName);
|
|
435
|
+
let entries = Object.entries(self._stories);
|
|
436
|
+
if (self._meta.title = this._options.makeTitle(self._meta?.title), self._metaAnnotations.play && (self._meta.tags = [...self._meta.tags || [], "play-fn"]), self._stories = entries.reduce(
|
|
437
|
+
(acc, [key, story]) => {
|
|
438
|
+
if (!isExportStory(key, self._meta))
|
|
439
|
+
return acc;
|
|
440
|
+
let id = story.parameters?.__id ?? toId(self._meta?.id || self._meta?.title, storyNameFromExport(key)), parameters = { ...story.parameters, __id: id }, { includeStories } = self._meta || {};
|
|
441
|
+
key === "__page" && (entries.length === 1 || Array.isArray(includeStories) && includeStories.length === 1) && (parameters.docsOnly = !0), acc[key] = { ...story, id, parameters };
|
|
442
|
+
let storyAnnotations = self._storyAnnotations[key], { tags, play } = storyAnnotations;
|
|
443
|
+
if (tags) {
|
|
444
|
+
let node = t2.isIdentifier(tags) ? findVarInitialization(tags.name, this._ast.program) : tags;
|
|
445
|
+
acc[key].tags = parseTags(node);
|
|
446
|
+
}
|
|
447
|
+
play && (acc[key].tags = [...acc[key].tags || [], "play-fn"]);
|
|
448
|
+
let stats = acc[key].__stats;
|
|
449
|
+
["play", "render", "loaders", "beforeEach", "globals", "tags"].forEach((annotation) => {
|
|
450
|
+
stats[annotation] = !!storyAnnotations[annotation] || !!self._metaAnnotations[annotation];
|
|
451
|
+
});
|
|
452
|
+
let storyExport = self.getStoryExport(key);
|
|
453
|
+
stats.storyFn = !!(t2.isArrowFunctionExpression(storyExport) || t2.isFunctionDeclaration(storyExport)), stats.mount = hasMount(storyAnnotations.play ?? self._metaAnnotations.play), stats.moduleMock = !!self.imports.find((fname) => isModuleMock(fname));
|
|
454
|
+
let storyNode = self._storyStatements[key], storyTests = self._tests.filter((t7) => t7.parent.node === storyNode);
|
|
455
|
+
return storyTests.length > 0 && (stats.tests = !0, storyTests.forEach((test) => {
|
|
456
|
+
test.id = toTestId(id, test.name);
|
|
457
|
+
})), acc;
|
|
458
|
+
},
|
|
459
|
+
{}
|
|
460
|
+
), Object.keys(self._storyExports).forEach((key) => {
|
|
461
|
+
isExportStory(key, self._meta) || (delete self._storyExports[key], delete self._storyAnnotations[key], delete self._storyStatements[key]);
|
|
462
|
+
}), self._namedExportsOrder) {
|
|
463
|
+
let unsortedExports = Object.keys(self._storyExports);
|
|
464
|
+
self._storyExports = sortExports(self._storyExports, self._namedExportsOrder), self._stories = sortExports(self._stories, self._namedExportsOrder);
|
|
465
|
+
let sortedExports = Object.keys(self._storyExports);
|
|
466
|
+
if (unsortedExports.length !== sortedExports.length)
|
|
467
|
+
throw new Error(
|
|
468
|
+
`Missing exports after sort: ${unsortedExports.filter(
|
|
469
|
+
(key) => !sortedExports.includes(key)
|
|
470
|
+
)}`
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
return self;
|
|
474
|
+
}
|
|
475
|
+
get meta() {
|
|
476
|
+
return this._meta;
|
|
477
|
+
}
|
|
478
|
+
get stories() {
|
|
479
|
+
return Object.values(this._stories);
|
|
480
|
+
}
|
|
481
|
+
getStoryTests(story) {
|
|
482
|
+
let storyNode = typeof story == "string" ? this._storyStatements[story] : story;
|
|
483
|
+
return storyNode ? this._tests.filter((t7) => t7.parent.node === storyNode) : [];
|
|
484
|
+
}
|
|
485
|
+
get indexInputs() {
|
|
486
|
+
let { fileName } = this._options;
|
|
487
|
+
if (!fileName)
|
|
488
|
+
throw new Error(
|
|
489
|
+
import_ts_dedent.dedent`Cannot automatically create index inputs with CsfFile.indexInputs because the CsfFile instance was created without a the fileName option.
|
|
490
|
+
Either add the fileName option when creating the CsfFile instance, or create the index inputs manually.`
|
|
491
|
+
);
|
|
492
|
+
let index = [];
|
|
493
|
+
return Object.entries(this._stories).map(([exportName, story]) => {
|
|
494
|
+
let tags = [...this._meta?.tags ?? [], ...story.tags ?? []], storyInput = {
|
|
495
|
+
importPath: fileName,
|
|
496
|
+
rawComponentPath: this._rawComponentPath,
|
|
497
|
+
exportName,
|
|
498
|
+
title: this.meta?.title,
|
|
499
|
+
metaId: this.meta?.id,
|
|
500
|
+
tags,
|
|
501
|
+
__id: story.id,
|
|
502
|
+
__stats: story.__stats
|
|
503
|
+
}, tests = this.getStoryTests(exportName), hasTests = tests.length > 0;
|
|
504
|
+
index.push({
|
|
505
|
+
...storyInput,
|
|
506
|
+
type: "story",
|
|
507
|
+
subtype: "story",
|
|
508
|
+
name: story.name
|
|
509
|
+
}), hasTests && tests.forEach((test) => {
|
|
510
|
+
index.push({
|
|
511
|
+
...storyInput,
|
|
512
|
+
// TODO implementent proper title => path behavior in `transformStoryIndexToStoriesHash`
|
|
513
|
+
// title: `${storyInput.title}/${story.name}`,
|
|
514
|
+
type: "story",
|
|
515
|
+
subtype: "test",
|
|
516
|
+
name: test.name,
|
|
517
|
+
parent: story.id,
|
|
518
|
+
parentName: story.name,
|
|
519
|
+
tags: [
|
|
520
|
+
...storyInput.tags,
|
|
521
|
+
// this tag comes before test tags so users can invert if they like
|
|
522
|
+
"!autodocs",
|
|
523
|
+
...test.tags,
|
|
524
|
+
// this tag comes after test tags so users can't change it
|
|
525
|
+
"test-fn"
|
|
526
|
+
],
|
|
527
|
+
__id: test.id
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
}), index;
|
|
531
|
+
}
|
|
532
|
+
}, babelParseFile = ({
|
|
533
|
+
code,
|
|
534
|
+
filename = "",
|
|
535
|
+
ast
|
|
536
|
+
}) => new BabelFileClass(
|
|
537
|
+
{ filename, highlightCode: !1 },
|
|
538
|
+
{ code, ast: ast ?? babelParse(code) }
|
|
539
|
+
), loadCsf = (code, options) => {
|
|
540
|
+
let ast = babelParse(code), file = babelParseFile({ code, filename: options.fileName, ast });
|
|
541
|
+
return new CsfFile(ast, options, file);
|
|
542
|
+
}, formatCsf = (csf, options = { sourceMaps: !1 }, code) => {
|
|
543
|
+
let result = generate(csf._ast, options, code);
|
|
544
|
+
return options.sourceMaps ? result : result.code;
|
|
545
|
+
}, printCsf = (csf, options = {}) => recast.print(csf._ast, options), readCsf = async (fileName, options) => {
|
|
546
|
+
let code = (await readFile(fileName, "utf-8")).toString();
|
|
547
|
+
return loadCsf(code, { ...options, fileName });
|
|
548
|
+
}, writeCsf = async (csf, fileName) => {
|
|
549
|
+
if (!(fileName || csf._options.fileName))
|
|
550
|
+
throw new Error("Please specify a fileName for writeCsf");
|
|
551
|
+
await writeFile(fileName, printCsf(csf).code);
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
// src/csf-tools/ConfigFile.ts
|
|
555
|
+
var import_ts_dedent2 = __toESM(require_dist(), 1);
|
|
556
|
+
import { readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
557
|
+
import {
|
|
558
|
+
babelParse as babelParse2,
|
|
559
|
+
generate as generate2,
|
|
560
|
+
recast as recast2,
|
|
561
|
+
types as t3,
|
|
562
|
+
traverse as traverse2
|
|
563
|
+
} from "storybook/internal/babel";
|
|
564
|
+
import { logger as logger2 } from "storybook/internal/node-logger";
|
|
565
|
+
var getCsfParsingErrorMessage = ({
|
|
566
|
+
expectedType,
|
|
567
|
+
foundType,
|
|
568
|
+
node
|
|
569
|
+
}) => import_ts_dedent2.dedent`
|
|
570
|
+
CSF Parsing error: Expected '${expectedType}' but found '${foundType}' instead in '${node?.type}'.
|
|
571
|
+
`, propKey = (p) => t3.isIdentifier(p.key) ? p.key.name : t3.isStringLiteral(p.key) ? p.key.value : null, _getPath = (path, node) => {
|
|
572
|
+
if (path.length === 0)
|
|
573
|
+
return node;
|
|
574
|
+
if (t3.isObjectExpression(node)) {
|
|
575
|
+
let [first, ...rest] = path, field = node.properties.find((p) => propKey(p) === first);
|
|
576
|
+
if (field)
|
|
577
|
+
return _getPath(rest, field.value);
|
|
578
|
+
}
|
|
579
|
+
}, _getPathProperties = (path, node) => {
|
|
580
|
+
if (path.length === 0) {
|
|
581
|
+
if (t3.isObjectExpression(node))
|
|
582
|
+
return node.properties;
|
|
583
|
+
throw new Error("Expected object expression");
|
|
584
|
+
}
|
|
585
|
+
if (t3.isObjectExpression(node)) {
|
|
586
|
+
let [first, ...rest] = path, field = node.properties.find((p) => propKey(p) === first);
|
|
587
|
+
if (field)
|
|
588
|
+
return rest.length === 0 ? node.properties : _getPathProperties(rest, field.value);
|
|
589
|
+
}
|
|
590
|
+
}, _findVarDeclarator = (identifier, program) => {
|
|
591
|
+
let declarator = null, declarations = null;
|
|
592
|
+
return program.body.find((node) => (t3.isVariableDeclaration(node) ? declarations = node.declarations : t3.isExportNamedDeclaration(node) && t3.isVariableDeclaration(node.declaration) && (declarations = node.declaration.declarations), declarations && declarations.find((decl) => t3.isVariableDeclarator(decl) && t3.isIdentifier(decl.id) && decl.id.name === identifier ? (declarator = decl, !0) : !1))), declarator;
|
|
593
|
+
}, _findVarInitialization = (identifier, program) => _findVarDeclarator(identifier, program)?.init, _makeObjectExpression = (path, value) => {
|
|
594
|
+
if (path.length === 0)
|
|
595
|
+
return value;
|
|
596
|
+
let [first, ...rest] = path, innerExpression = _makeObjectExpression(rest, value);
|
|
597
|
+
return t3.objectExpression([t3.objectProperty(t3.identifier(first), innerExpression)]);
|
|
598
|
+
}, _updateExportNode = (path, expr, existing) => {
|
|
599
|
+
let [first, ...rest] = path, existingField = existing.properties.find(
|
|
600
|
+
(p) => propKey(p) === first
|
|
601
|
+
);
|
|
602
|
+
existingField ? t3.isObjectExpression(existingField.value) && rest.length > 0 ? _updateExportNode(rest, expr, existingField.value) : existingField.value = _makeObjectExpression(rest, expr) : existing.properties.push(
|
|
603
|
+
t3.objectProperty(t3.identifier(first), _makeObjectExpression(rest, expr))
|
|
604
|
+
);
|
|
605
|
+
}, ConfigFile = class {
|
|
606
|
+
constructor(ast, code, fileName) {
|
|
607
|
+
this._exports = {};
|
|
608
|
+
// FIXME: this is a hack. this is only used in the case where the user is
|
|
609
|
+
// modifying a named export that's a scalar. The _exports map is not suitable
|
|
610
|
+
// for that. But rather than refactor the whole thing, we just use this as a stopgap.
|
|
611
|
+
this._exportDecls = {};
|
|
612
|
+
this.hasDefaultExport = !1;
|
|
613
|
+
/** Unwraps TS assertions/satisfies from a node, to get the underlying node. */
|
|
614
|
+
this._unwrap = (node) => t3.isTSAsExpression(node) || t3.isTSSatisfiesExpression(node) ? this._unwrap(node.expression) : node;
|
|
615
|
+
/**
|
|
616
|
+
* Resolve a declaration node by unwrapping TS assertions/satisfies and following identifiers to
|
|
617
|
+
* resolve the correct node in case it's an identifier.
|
|
618
|
+
*/
|
|
619
|
+
this._resolveDeclaration = (node, parent = this._ast.program) => {
|
|
620
|
+
let decl = this._unwrap(node);
|
|
621
|
+
if (t3.isIdentifier(decl) && t3.isProgram(parent)) {
|
|
622
|
+
let initialization = _findVarInitialization(decl.name, parent);
|
|
623
|
+
return initialization ? this._unwrap(initialization) : decl;
|
|
624
|
+
}
|
|
625
|
+
return decl;
|
|
626
|
+
};
|
|
627
|
+
this._ast = ast, this._code = code, this.fileName = fileName;
|
|
628
|
+
}
|
|
629
|
+
_parseExportsObject(exportsObject) {
|
|
630
|
+
this._exportsObject = exportsObject, exportsObject.properties.forEach((p) => {
|
|
631
|
+
let exportName = propKey(p);
|
|
632
|
+
if (exportName) {
|
|
633
|
+
let exportVal = this._resolveDeclaration(p.value);
|
|
634
|
+
this._exports[exportName] = exportVal;
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
parse() {
|
|
639
|
+
let self = this;
|
|
640
|
+
return traverse2(this._ast, {
|
|
641
|
+
ExportDefaultDeclaration: {
|
|
642
|
+
enter({ node, parent }) {
|
|
643
|
+
self.hasDefaultExport = !0;
|
|
644
|
+
let decl = self._resolveDeclaration(node.declaration, parent);
|
|
645
|
+
t3.isCallExpression(decl) && t3.isObjectExpression(decl.arguments[0]) && (decl = decl.arguments[0]), t3.isObjectExpression(decl) ? self._parseExportsObject(decl) : logger2.warn(
|
|
646
|
+
getCsfParsingErrorMessage({
|
|
647
|
+
expectedType: "ObjectExpression",
|
|
648
|
+
foundType: decl?.type,
|
|
649
|
+
node: decl || node.declaration
|
|
650
|
+
})
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
},
|
|
654
|
+
ExportNamedDeclaration: {
|
|
655
|
+
enter({ node, parent }) {
|
|
656
|
+
if (t3.isVariableDeclaration(node.declaration))
|
|
657
|
+
node.declaration.declarations.forEach((decl) => {
|
|
658
|
+
if (t3.isVariableDeclarator(decl) && t3.isIdentifier(decl.id)) {
|
|
659
|
+
let { name: exportName } = decl.id, exportVal = self._resolveDeclaration(decl.init, parent);
|
|
660
|
+
self._exports[exportName] = exportVal, self._exportDecls[exportName] = decl;
|
|
661
|
+
}
|
|
662
|
+
});
|
|
663
|
+
else if (t3.isFunctionDeclaration(node.declaration)) {
|
|
664
|
+
let decl = node.declaration;
|
|
665
|
+
if (t3.isIdentifier(decl.id)) {
|
|
666
|
+
let { name: exportName } = decl.id;
|
|
667
|
+
self._exportDecls[exportName] = decl;
|
|
668
|
+
}
|
|
669
|
+
} else node.specifiers ? node.specifiers.forEach((spec) => {
|
|
670
|
+
if (t3.isExportSpecifier(spec) && t3.isIdentifier(spec.local) && t3.isIdentifier(spec.exported)) {
|
|
671
|
+
let { name: localName } = spec.local, { name: exportName } = spec.exported, decl = _findVarDeclarator(localName, parent);
|
|
672
|
+
decl && (self._exports[exportName] = self._resolveDeclaration(decl.init, parent), self._exportDecls[exportName] = decl);
|
|
673
|
+
}
|
|
674
|
+
}) : logger2.warn(
|
|
675
|
+
getCsfParsingErrorMessage({
|
|
676
|
+
expectedType: "VariableDeclaration",
|
|
677
|
+
foundType: node.declaration?.type,
|
|
678
|
+
node: node.declaration
|
|
679
|
+
})
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
},
|
|
683
|
+
ExpressionStatement: {
|
|
684
|
+
enter({ node, parent }) {
|
|
685
|
+
if (t3.isAssignmentExpression(node.expression) && node.expression.operator === "=") {
|
|
686
|
+
let { left, right } = node.expression;
|
|
687
|
+
if (t3.isMemberExpression(left) && t3.isIdentifier(left.object) && left.object.name === "module" && t3.isIdentifier(left.property) && left.property.name === "exports") {
|
|
688
|
+
let exportObject = right;
|
|
689
|
+
exportObject = self._resolveDeclaration(exportObject, parent), t3.isObjectExpression(exportObject) ? (self._exportsObject = exportObject, exportObject.properties.forEach((p) => {
|
|
690
|
+
let exportName = propKey(p);
|
|
691
|
+
if (exportName) {
|
|
692
|
+
let exportVal = self._resolveDeclaration(p.value, parent);
|
|
693
|
+
self._exports[exportName] = exportVal;
|
|
694
|
+
}
|
|
695
|
+
})) : logger2.warn(
|
|
696
|
+
getCsfParsingErrorMessage({
|
|
697
|
+
expectedType: "ObjectExpression",
|
|
698
|
+
foundType: exportObject?.type,
|
|
699
|
+
node: exportObject
|
|
700
|
+
})
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
CallExpression: {
|
|
707
|
+
enter: ({ node }) => {
|
|
708
|
+
t3.isIdentifier(node.callee) && node.callee.name === "definePreview" && node.arguments.length === 1 && t3.isObjectExpression(node.arguments[0]) && self._parseExportsObject(node.arguments[0]);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}), self;
|
|
712
|
+
}
|
|
713
|
+
getFieldNode(path) {
|
|
714
|
+
let [root, ...rest] = path, exported = this._exports[root];
|
|
715
|
+
if (exported)
|
|
716
|
+
return _getPath(rest, exported);
|
|
717
|
+
}
|
|
718
|
+
getFieldProperties(path) {
|
|
719
|
+
let [root, ...rest] = path, exported = this._exports[root];
|
|
720
|
+
if (exported)
|
|
721
|
+
return _getPathProperties(rest, exported);
|
|
722
|
+
}
|
|
723
|
+
getFieldValue(path) {
|
|
724
|
+
let node = this.getFieldNode(path);
|
|
725
|
+
if (node) {
|
|
726
|
+
let { code } = generate2(node, {});
|
|
727
|
+
return (0, eval)(`(() => (${code}))()`);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
getSafeFieldValue(path) {
|
|
731
|
+
try {
|
|
732
|
+
return this.getFieldValue(path);
|
|
733
|
+
} catch {
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
setFieldNode(path, expr) {
|
|
737
|
+
let [first, ...rest] = path, exportNode = this._exports[first];
|
|
738
|
+
if (this._exportsObject) {
|
|
739
|
+
let existingProp = this._exportsObject.properties.find((p) => propKey(p) === first);
|
|
740
|
+
if (existingProp && t3.isIdentifier(existingProp.value)) {
|
|
741
|
+
let varDecl2 = _findVarDeclarator(existingProp.value.name, this._ast.program);
|
|
742
|
+
if (varDecl2 && t3.isObjectExpression(varDecl2.init)) {
|
|
743
|
+
_updateExportNode(rest, expr, varDecl2.init);
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
_updateExportNode(path, expr, this._exportsObject), this._exports[path[0]] = expr;
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
if (exportNode && t3.isObjectExpression(exportNode) && rest.length > 0) {
|
|
751
|
+
_updateExportNode(rest, expr, exportNode);
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
let varDecl = _findVarDeclarator(first, this._ast.program);
|
|
755
|
+
if (varDecl && t3.isObjectExpression(varDecl.init)) {
|
|
756
|
+
_updateExportNode(rest, expr, varDecl.init);
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
if (exportNode && rest.length === 0 && this._exportDecls[path[0]]) {
|
|
760
|
+
let decl = this._exportDecls[path[0]];
|
|
761
|
+
t3.isVariableDeclarator(decl) && (decl.init = _makeObjectExpression([], expr));
|
|
762
|
+
} else {
|
|
763
|
+
if (this.hasDefaultExport)
|
|
764
|
+
throw new Error(
|
|
765
|
+
`Could not set the "${path.join(
|
|
766
|
+
"."
|
|
767
|
+
)}" field as the default export is not an object in this file.`
|
|
768
|
+
);
|
|
769
|
+
{
|
|
770
|
+
let exportObj = _makeObjectExpression(rest, expr), newExport = t3.exportNamedDeclaration(
|
|
771
|
+
t3.variableDeclaration("const", [t3.variableDeclarator(t3.identifier(first), exportObj)])
|
|
772
|
+
);
|
|
773
|
+
this._exports[first] = exportObj, this._ast.program.body.push(newExport);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* @example
|
|
779
|
+
*
|
|
780
|
+
* ```ts
|
|
781
|
+
* // 1. { framework: 'framework-name' }
|
|
782
|
+
* // 2. { framework: { name: 'framework-name', options: {} }
|
|
783
|
+
* getNameFromPath(['framework']); // => 'framework-name'
|
|
784
|
+
* ```
|
|
785
|
+
*
|
|
786
|
+
* @returns The name of a node in a given path, supporting the following formats:
|
|
787
|
+
*/
|
|
788
|
+
getNameFromPath(path) {
|
|
789
|
+
let node = this.getFieldNode(path);
|
|
790
|
+
if (node)
|
|
791
|
+
return this._getPresetValue(node, "name");
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Returns an array of names of a node in a given path, supporting the following formats:
|
|
795
|
+
*
|
|
796
|
+
* @example
|
|
797
|
+
*
|
|
798
|
+
* ```ts
|
|
799
|
+
* const config = {
|
|
800
|
+
* addons: ['first-addon', { name: 'second-addon', options: {} }],
|
|
801
|
+
* };
|
|
802
|
+
* // => ['first-addon', 'second-addon']
|
|
803
|
+
* getNamesFromPath(['addons']);
|
|
804
|
+
* ```
|
|
805
|
+
*/
|
|
806
|
+
getNamesFromPath(path) {
|
|
807
|
+
let node = this.getFieldNode(path);
|
|
808
|
+
if (!node)
|
|
809
|
+
return;
|
|
810
|
+
let pathNames = [];
|
|
811
|
+
return t3.isArrayExpression(node) && node.elements.forEach((element) => {
|
|
812
|
+
pathNames.push(this._getPresetValue(element, "name"));
|
|
813
|
+
}), pathNames;
|
|
814
|
+
}
|
|
815
|
+
_getPnpWrappedValue(node) {
|
|
816
|
+
if (t3.isCallExpression(node)) {
|
|
817
|
+
let arg = node.arguments[0];
|
|
818
|
+
if (t3.isStringLiteral(arg))
|
|
819
|
+
return arg.value;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Given a node and a fallback property, returns a **non-evaluated** string value of the node.
|
|
824
|
+
*
|
|
825
|
+
* 1. `{ node: 'value' }`
|
|
826
|
+
* 2. `{ node: { fallbackProperty: 'value' } }`
|
|
827
|
+
*/
|
|
828
|
+
_getPresetValue(node, fallbackProperty) {
|
|
829
|
+
let value;
|
|
830
|
+
if (t3.isStringLiteral(node) ? value = node.value : t3.isObjectExpression(node) ? node.properties.forEach((prop) => {
|
|
831
|
+
t3.isObjectProperty(prop) && t3.isIdentifier(prop.key) && prop.key.name === fallbackProperty && (t3.isStringLiteral(prop.value) ? value = prop.value.value : value = this._getPnpWrappedValue(prop.value)), t3.isObjectProperty(prop) && t3.isStringLiteral(prop.key) && prop.key.value === "name" && t3.isStringLiteral(prop.value) && (value = prop.value.value);
|
|
832
|
+
}) : t3.isCallExpression(node) && (value = this._getPnpWrappedValue(node)), !value)
|
|
833
|
+
throw new Error(
|
|
834
|
+
`The given node must be a string literal or an object expression with a "${fallbackProperty}" property that is a string literal.`
|
|
835
|
+
);
|
|
836
|
+
return value;
|
|
837
|
+
}
|
|
838
|
+
removeField(path) {
|
|
839
|
+
let removeProperty = (properties2, prop) => {
|
|
840
|
+
let index = properties2.findIndex(
|
|
841
|
+
(p) => t3.isIdentifier(p.key) && p.key.name === prop || t3.isStringLiteral(p.key) && p.key.value === prop
|
|
842
|
+
);
|
|
843
|
+
index >= 0 && properties2.splice(index, 1);
|
|
844
|
+
};
|
|
845
|
+
if (path.length === 1) {
|
|
846
|
+
let removedRootProperty = !1;
|
|
847
|
+
if (this._ast.program.body.forEach((node) => {
|
|
848
|
+
if (t3.isExportNamedDeclaration(node) && t3.isVariableDeclaration(node.declaration)) {
|
|
849
|
+
let decl = node.declaration.declarations[0];
|
|
850
|
+
t3.isIdentifier(decl.id) && decl.id.name === path[0] && (this._ast.program.body.splice(this._ast.program.body.indexOf(node), 1), removedRootProperty = !0);
|
|
851
|
+
}
|
|
852
|
+
if (t3.isExportDefaultDeclaration(node)) {
|
|
853
|
+
let resolved = this._resolveDeclaration(node.declaration);
|
|
854
|
+
if (t3.isObjectExpression(resolved)) {
|
|
855
|
+
let properties2 = resolved.properties;
|
|
856
|
+
removeProperty(properties2, path[0]), removedRootProperty = !0;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
if (t3.isExpressionStatement(node) && t3.isAssignmentExpression(node.expression) && t3.isMemberExpression(node.expression.left) && t3.isIdentifier(node.expression.left.object) && node.expression.left.object.name === "module" && t3.isIdentifier(node.expression.left.property) && node.expression.left.property.name === "exports" && t3.isObjectExpression(node.expression.right)) {
|
|
860
|
+
let properties2 = node.expression.right.properties;
|
|
861
|
+
removeProperty(properties2, path[0]), removedRootProperty = !0;
|
|
862
|
+
}
|
|
863
|
+
}), removedRootProperty)
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
let properties = this.getFieldProperties(path);
|
|
867
|
+
if (properties) {
|
|
868
|
+
let lastPath = path.at(-1);
|
|
869
|
+
removeProperty(properties, lastPath);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
appendValueToArray(path, value) {
|
|
873
|
+
let node = this.valueToNode(value);
|
|
874
|
+
node && this.appendNodeToArray(path, node);
|
|
875
|
+
}
|
|
876
|
+
appendNodeToArray(path, node) {
|
|
877
|
+
let current = this.getFieldNode(path);
|
|
878
|
+
if (!current)
|
|
879
|
+
this.setFieldNode(path, t3.arrayExpression([node]));
|
|
880
|
+
else if (t3.isArrayExpression(current))
|
|
881
|
+
current.elements.push(node);
|
|
882
|
+
else
|
|
883
|
+
throw new Error(`Expected array at '${path.join(".")}', got '${current.type}'`);
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Specialized helper to remove addons or other array entries that can either be strings or
|
|
887
|
+
* objects with a name property.
|
|
888
|
+
*/
|
|
889
|
+
removeEntryFromArray(path, value) {
|
|
890
|
+
let current = this.getFieldNode(path);
|
|
891
|
+
if (current)
|
|
892
|
+
if (t3.isArrayExpression(current)) {
|
|
893
|
+
let index = current.elements.findIndex((element) => t3.isStringLiteral(element) ? element.value === value : t3.isObjectExpression(element) ? this._getPresetValue(element, "name") === value : this._getPnpWrappedValue(element) === value);
|
|
894
|
+
if (index >= 0)
|
|
895
|
+
current.elements.splice(index, 1);
|
|
896
|
+
else
|
|
897
|
+
throw new Error(`Could not find '${value}' in array at '${path.join(".")}'`);
|
|
898
|
+
} else
|
|
899
|
+
throw new Error(`Expected array at '${path.join(".")}', got '${current.type}'`);
|
|
900
|
+
}
|
|
901
|
+
_inferQuotes() {
|
|
902
|
+
if (!this._quotes) {
|
|
903
|
+
let occurrences = (this._ast.tokens || []).slice(0, 500).reduce(
|
|
904
|
+
(acc, token) => (token.type.label === "string" && (acc[this._code[token.start]] += 1), acc),
|
|
905
|
+
{ "'": 0, '"': 0 }
|
|
906
|
+
);
|
|
907
|
+
this._quotes = occurrences["'"] > occurrences['"'] ? "single" : "double";
|
|
908
|
+
}
|
|
909
|
+
return this._quotes;
|
|
910
|
+
}
|
|
911
|
+
valueToNode(value) {
|
|
912
|
+
let quotes = this._inferQuotes(), valueNode;
|
|
913
|
+
if (quotes === "single") {
|
|
914
|
+
let { code } = generate2(t3.valueToNode(value), { jsescOption: { quotes } }), program = babelParse2(`const __x = ${code}`);
|
|
915
|
+
traverse2(program, {
|
|
916
|
+
VariableDeclaration: {
|
|
917
|
+
enter({ node }) {
|
|
918
|
+
node.declarations.length === 1 && t3.isVariableDeclarator(node.declarations[0]) && t3.isIdentifier(node.declarations[0].id) && node.declarations[0].id.name === "__x" && (valueNode = node.declarations[0].init);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
} else
|
|
923
|
+
valueNode = t3.valueToNode(value);
|
|
924
|
+
return valueNode;
|
|
925
|
+
}
|
|
926
|
+
setFieldValue(path, value) {
|
|
927
|
+
let valueNode = this.valueToNode(value);
|
|
928
|
+
if (!valueNode)
|
|
929
|
+
throw new Error(`Unexpected value ${JSON.stringify(value)}`);
|
|
930
|
+
this.setFieldNode(path, valueNode);
|
|
931
|
+
}
|
|
932
|
+
getBodyDeclarations() {
|
|
933
|
+
return this._ast.program.body;
|
|
934
|
+
}
|
|
935
|
+
setBodyDeclaration(declaration) {
|
|
936
|
+
this._ast.program.body.push(declaration);
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Import specifiers for a specific require import
|
|
940
|
+
*
|
|
941
|
+
* @example
|
|
942
|
+
*
|
|
943
|
+
* ```ts
|
|
944
|
+
* // const { foo } = require('bar');
|
|
945
|
+
* setRequireImport(['foo'], 'bar');
|
|
946
|
+
*
|
|
947
|
+
* // const foo = require('bar');
|
|
948
|
+
* setRequireImport('foo', 'bar');
|
|
949
|
+
* ```
|
|
950
|
+
*
|
|
951
|
+
* @param importSpecifiers - The import specifiers to set. If a string is passed in, a default
|
|
952
|
+
* import will be set. Otherwise, an array of named imports will be set
|
|
953
|
+
* @param fromImport - The module to import from
|
|
954
|
+
*/
|
|
955
|
+
setRequireImport(importSpecifier, fromImport) {
|
|
956
|
+
let requireDeclaration = this._ast.program.body.find((node) => {
|
|
957
|
+
let hasDeclaration = t3.isVariableDeclaration(node) && node.declarations.length === 1 && t3.isVariableDeclarator(node.declarations[0]) && t3.isCallExpression(node.declarations[0].init) && t3.isIdentifier(node.declarations[0].init.callee) && node.declarations[0].init.callee.name === "require" && t3.isStringLiteral(node.declarations[0].init.arguments[0]) && (node.declarations[0].init.arguments[0].value === fromImport || node.declarations[0].init.arguments[0].value === fromImport.split("node:")[1]);
|
|
958
|
+
return hasDeclaration && (fromImport = node.declarations[0].init.arguments[0].value), hasDeclaration;
|
|
959
|
+
}), hasRequireSpecifier = (name) => t3.isObjectPattern(requireDeclaration?.declarations[0].id) && requireDeclaration?.declarations[0].id.properties.find(
|
|
960
|
+
(specifier) => t3.isObjectProperty(specifier) && t3.isIdentifier(specifier.key) && specifier.key.name === name
|
|
961
|
+
), hasDefaultRequireSpecifier = (declaration, name) => declaration.declarations.length === 1 && t3.isVariableDeclarator(declaration.declarations[0]) && t3.isIdentifier(declaration.declarations[0].id) && declaration.declarations[0].id.name === name;
|
|
962
|
+
if (typeof importSpecifier == "string") {
|
|
963
|
+
let addDefaultRequireSpecifier = () => {
|
|
964
|
+
this._ast.program.body.unshift(
|
|
965
|
+
t3.variableDeclaration("const", [
|
|
966
|
+
t3.variableDeclarator(
|
|
967
|
+
t3.identifier(importSpecifier),
|
|
968
|
+
t3.callExpression(t3.identifier("require"), [t3.stringLiteral(fromImport)])
|
|
969
|
+
)
|
|
970
|
+
])
|
|
971
|
+
);
|
|
972
|
+
};
|
|
973
|
+
requireDeclaration && hasDefaultRequireSpecifier(requireDeclaration, importSpecifier) || addDefaultRequireSpecifier();
|
|
974
|
+
} else requireDeclaration ? importSpecifier.forEach((specifier) => {
|
|
975
|
+
hasRequireSpecifier(specifier) || requireDeclaration.declarations[0].id.properties.push(
|
|
976
|
+
t3.objectProperty(t3.identifier(specifier), t3.identifier(specifier), void 0, !0)
|
|
977
|
+
);
|
|
978
|
+
}) : this._ast.program.body.unshift(
|
|
979
|
+
t3.variableDeclaration("const", [
|
|
980
|
+
t3.variableDeclarator(
|
|
981
|
+
t3.objectPattern(
|
|
982
|
+
importSpecifier.map(
|
|
983
|
+
(specifier) => t3.objectProperty(t3.identifier(specifier), t3.identifier(specifier), void 0, !0)
|
|
984
|
+
)
|
|
985
|
+
),
|
|
986
|
+
t3.callExpression(t3.identifier("require"), [t3.stringLiteral(fromImport)])
|
|
987
|
+
)
|
|
988
|
+
])
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Set import specifiers for a given import statement.
|
|
993
|
+
*
|
|
994
|
+
* Does not support setting type imports (yet)
|
|
995
|
+
*
|
|
996
|
+
* @example
|
|
997
|
+
*
|
|
998
|
+
* ```ts
|
|
999
|
+
* // import { foo } from 'bar';
|
|
1000
|
+
* setImport(['foo'], 'bar');
|
|
1001
|
+
*
|
|
1002
|
+
* // import foo from 'bar';
|
|
1003
|
+
* setImport('foo', 'bar');
|
|
1004
|
+
*
|
|
1005
|
+
* // import * as foo from 'bar';
|
|
1006
|
+
* setImport({ namespace: 'foo' }, 'bar');
|
|
1007
|
+
*
|
|
1008
|
+
* // import 'bar';
|
|
1009
|
+
* setImport(null, 'bar');
|
|
1010
|
+
* ```
|
|
1011
|
+
*
|
|
1012
|
+
* @param importSpecifiers - The import specifiers to set. If a string is passed in, a default
|
|
1013
|
+
* import will be set. Otherwise, an array of named imports will be set
|
|
1014
|
+
* @param fromImport - The module to import from
|
|
1015
|
+
*/
|
|
1016
|
+
setImport(importSpecifier, fromImport) {
|
|
1017
|
+
let importDeclaration = this._ast.program.body.find((node) => {
|
|
1018
|
+
let hasDeclaration = t3.isImportDeclaration(node) && (node.source.value === fromImport || node.source.value === fromImport.split("node:")[1]);
|
|
1019
|
+
return hasDeclaration && (fromImport = node.source.value), hasDeclaration;
|
|
1020
|
+
}), getNewImportSpecifier = (specifier) => t3.importSpecifier(t3.identifier(specifier), t3.identifier(specifier)), hasImportSpecifier = (declaration, name) => declaration.specifiers.find(
|
|
1021
|
+
(specifier) => t3.isImportSpecifier(specifier) && t3.isIdentifier(specifier.imported) && specifier.imported.name === name
|
|
1022
|
+
), hasNamespaceImportSpecifier = (declaration, name) => declaration.specifiers.find(
|
|
1023
|
+
(specifier) => t3.isImportNamespaceSpecifier(specifier) && t3.isIdentifier(specifier.local) && specifier.local.name === name
|
|
1024
|
+
);
|
|
1025
|
+
importSpecifier === null ? importDeclaration || this._ast.program.body.unshift(t3.importDeclaration([], t3.stringLiteral(fromImport))) : typeof importSpecifier == "string" ? importDeclaration ? ((declaration, name) => declaration.specifiers.find(
|
|
1026
|
+
(specifier) => t3.isImportDefaultSpecifier(specifier) && t3.isIdentifier(specifier.local) && specifier.local.name === name
|
|
1027
|
+
))(importDeclaration, importSpecifier) || importDeclaration.specifiers.push(
|
|
1028
|
+
t3.importDefaultSpecifier(t3.identifier(importSpecifier))
|
|
1029
|
+
) : this._ast.program.body.unshift(
|
|
1030
|
+
t3.importDeclaration(
|
|
1031
|
+
[t3.importDefaultSpecifier(t3.identifier(importSpecifier))],
|
|
1032
|
+
t3.stringLiteral(fromImport)
|
|
1033
|
+
)
|
|
1034
|
+
) : Array.isArray(importSpecifier) ? importDeclaration ? importSpecifier.forEach((specifier) => {
|
|
1035
|
+
hasImportSpecifier(importDeclaration, specifier) || importDeclaration.specifiers.push(getNewImportSpecifier(specifier));
|
|
1036
|
+
}) : this._ast.program.body.unshift(
|
|
1037
|
+
t3.importDeclaration(
|
|
1038
|
+
importSpecifier.map(getNewImportSpecifier),
|
|
1039
|
+
t3.stringLiteral(fromImport)
|
|
1040
|
+
)
|
|
1041
|
+
) : importSpecifier.namespace && (importDeclaration ? hasNamespaceImportSpecifier(importDeclaration, importSpecifier.namespace) || importDeclaration.specifiers.push(
|
|
1042
|
+
t3.importNamespaceSpecifier(t3.identifier(importSpecifier.namespace))
|
|
1043
|
+
) : this._ast.program.body.unshift(
|
|
1044
|
+
t3.importDeclaration(
|
|
1045
|
+
[t3.importNamespaceSpecifier(t3.identifier(importSpecifier.namespace))],
|
|
1046
|
+
t3.stringLiteral(fromImport)
|
|
1047
|
+
)
|
|
1048
|
+
));
|
|
1049
|
+
}
|
|
1050
|
+
_removeRequireImport(importSpecifier, fromImport) {
|
|
1051
|
+
let requireDeclarationIndex = this._ast.program.body.findIndex((node) => t3.isVariableDeclaration(node) && node.declarations.length === 1 && t3.isVariableDeclarator(node.declarations[0]) && t3.isCallExpression(node.declarations[0].init) && t3.isIdentifier(node.declarations[0].init.callee) && node.declarations[0].init.callee.name === "require" && t3.isStringLiteral(node.declarations[0].init.arguments[0]) && (node.declarations[0].init.arguments[0].value === fromImport || node.declarations[0].init.arguments[0].value === fromImport.split("node:")[1]));
|
|
1052
|
+
if (requireDeclarationIndex === -1)
|
|
1053
|
+
return;
|
|
1054
|
+
let declarator = this._ast.program.body[requireDeclarationIndex].declarations[0];
|
|
1055
|
+
if (importSpecifier !== null) {
|
|
1056
|
+
if (typeof importSpecifier == "string") {
|
|
1057
|
+
t3.isIdentifier(declarator.id) && declarator.id.name === importSpecifier && this._ast.program.body.splice(requireDeclarationIndex, 1);
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
if (!(typeof importSpecifier == "object" && "namespace" in importSpecifier) && Array.isArray(importSpecifier) && t3.isObjectPattern(declarator.id)) {
|
|
1061
|
+
let objectPattern = declarator.id;
|
|
1062
|
+
importSpecifier.forEach((specifier) => {
|
|
1063
|
+
let index = objectPattern.properties.findIndex(
|
|
1064
|
+
(prop) => t3.isObjectProperty(prop) && t3.isIdentifier(prop.key) && prop.key.name === specifier
|
|
1065
|
+
);
|
|
1066
|
+
index !== -1 && objectPattern.properties.splice(index, 1);
|
|
1067
|
+
}), objectPattern.properties.length === 0 && this._ast.program.body.splice(requireDeclarationIndex, 1);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
_removeImport(importSpecifier, fromImport) {
|
|
1072
|
+
let importDeclarationIndex = this._ast.program.body.findIndex(
|
|
1073
|
+
(node) => t3.isImportDeclaration(node) && (node.source.value === fromImport || node.source.value === fromImport.split("node:")[1])
|
|
1074
|
+
);
|
|
1075
|
+
if (importDeclarationIndex === -1)
|
|
1076
|
+
return;
|
|
1077
|
+
let importDeclaration = this._ast.program.body[importDeclarationIndex];
|
|
1078
|
+
if (importSpecifier === null) {
|
|
1079
|
+
importDeclaration.specifiers.length === 0 && this._ast.program.body.splice(importDeclarationIndex, 1);
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
if (typeof importSpecifier == "object" && "namespace" in importSpecifier) {
|
|
1083
|
+
let index = importDeclaration.specifiers.findIndex(
|
|
1084
|
+
(specifier) => t3.isImportNamespaceSpecifier(specifier) && t3.isIdentifier(specifier.local) && specifier.local.name === importSpecifier.namespace
|
|
1085
|
+
);
|
|
1086
|
+
index !== -1 && importDeclaration.specifiers.splice(index, 1);
|
|
1087
|
+
}
|
|
1088
|
+
if (typeof importSpecifier == "string") {
|
|
1089
|
+
let index = importDeclaration.specifiers.findIndex(
|
|
1090
|
+
(specifier) => t3.isImportDefaultSpecifier(specifier) && t3.isIdentifier(specifier.local) && specifier.local.name === importSpecifier
|
|
1091
|
+
);
|
|
1092
|
+
index !== -1 && importDeclaration.specifiers.splice(index, 1);
|
|
1093
|
+
}
|
|
1094
|
+
Array.isArray(importSpecifier) && importSpecifier.forEach((specifier) => {
|
|
1095
|
+
let index = importDeclaration.specifiers.findIndex(
|
|
1096
|
+
(current) => t3.isImportSpecifier(current) && t3.isIdentifier(current.imported) && current.imported.name === specifier
|
|
1097
|
+
);
|
|
1098
|
+
index !== -1 && importDeclaration.specifiers.splice(index, 1);
|
|
1099
|
+
}), importDeclaration.specifiers.length === 0 && this._ast.program.body.splice(importDeclarationIndex, 1);
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Remove import specifiers for a given import statement.
|
|
1103
|
+
*
|
|
1104
|
+
* Does not support removing type imports (yet)
|
|
1105
|
+
*
|
|
1106
|
+
* @example
|
|
1107
|
+
*
|
|
1108
|
+
* ```ts
|
|
1109
|
+
* // import { foo } from 'bar';
|
|
1110
|
+
* setImport(['foo'], 'bar');
|
|
1111
|
+
*
|
|
1112
|
+
* // import foo from 'bar';
|
|
1113
|
+
* setImport('foo', 'bar');
|
|
1114
|
+
*
|
|
1115
|
+
* // import * as foo from 'bar';
|
|
1116
|
+
* setImport({ namespace: 'foo' }, 'bar');
|
|
1117
|
+
*
|
|
1118
|
+
* // import 'bar';
|
|
1119
|
+
* setImport(null, 'bar');
|
|
1120
|
+
* ```
|
|
1121
|
+
*
|
|
1122
|
+
* @param importSpecifiers - The import specifiers to remove. If a string is passed in, will only
|
|
1123
|
+
* remove the default import. Otherwise, named imports matching the array will be removed.
|
|
1124
|
+
* @param fromImport - The module to import from
|
|
1125
|
+
*/
|
|
1126
|
+
removeImport(importSpecifier, fromImport) {
|
|
1127
|
+
this._removeRequireImport(importSpecifier, fromImport), this._removeImport(importSpecifier, fromImport);
|
|
1128
|
+
}
|
|
1129
|
+
}, loadConfig = (code, fileName) => {
|
|
1130
|
+
let ast = babelParse2(code);
|
|
1131
|
+
return new ConfigFile(ast, code, fileName);
|
|
1132
|
+
}, formatConfig = (config) => printConfig(config).code, printConfig = (config, options = {}) => recast2.print(config._ast, options), readConfig = async (fileName) => {
|
|
1133
|
+
let code = (await readFile2(fileName, "utf-8")).toString();
|
|
1134
|
+
return loadConfig(code, fileName).parse();
|
|
1135
|
+
}, writeConfig = async (config, fileName) => {
|
|
1136
|
+
let fname = fileName || config.fileName;
|
|
1137
|
+
if (!fname)
|
|
1138
|
+
throw new Error("Please specify a fileName for writeConfig");
|
|
1139
|
+
await writeFile2(fname, formatConfig(config));
|
|
1140
|
+
}, isCsfFactoryPreview = (previewConfig) => !!previewConfig._ast.program.body.find((node) => t3.isImportDeclaration(node) && node.source.value.includes("@storybook") && node.specifiers.some((specifier) => t3.isImportSpecifier(specifier) && t3.isIdentifier(specifier.imported) && specifier.imported.name === "definePreview"));
|
|
1141
|
+
|
|
1142
|
+
// src/csf-tools/getStorySortParameter.ts
|
|
1143
|
+
var import_ts_dedent3 = __toESM(require_dist(), 1);
|
|
1144
|
+
import { babelParse as babelParse3, generate as generate3, types as t4, traverse as traverse3 } from "storybook/internal/babel";
|
|
1145
|
+
import { logger as logger3 } from "storybook/internal/node-logger";
|
|
1146
|
+
var getValue = (obj, key) => {
|
|
1147
|
+
let value;
|
|
1148
|
+
return obj.properties.forEach((p) => {
|
|
1149
|
+
t4.isIdentifier(p.key) && p.key.name === key && (value = p.value);
|
|
1150
|
+
}), value;
|
|
1151
|
+
}, parseValue = (value) => {
|
|
1152
|
+
let expr = stripTSModifiers(value);
|
|
1153
|
+
if (t4.isArrayExpression(expr))
|
|
1154
|
+
return expr.elements.map((o) => parseValue(o));
|
|
1155
|
+
if (t4.isObjectExpression(expr))
|
|
1156
|
+
return expr.properties.reduce((acc, p) => (t4.isIdentifier(p.key) && (acc[p.key.name] = parseValue(p.value)), acc), {});
|
|
1157
|
+
if (t4.isLiteral(expr))
|
|
1158
|
+
return expr.value;
|
|
1159
|
+
if (t4.isIdentifier(expr))
|
|
1160
|
+
return unsupported(expr.name, !0);
|
|
1161
|
+
throw new Error(`Unknown node type ${expr.type}`);
|
|
1162
|
+
}, unsupported = (unexpectedVar, isError) => {
|
|
1163
|
+
let message = import_ts_dedent3.dedent`
|
|
1164
|
+
Unexpected '${unexpectedVar}'. Parameter 'options.storySort' should be defined inline e.g.:
|
|
1165
|
+
|
|
1166
|
+
export default {
|
|
1167
|
+
parameters: {
|
|
1168
|
+
options: {
|
|
1169
|
+
storySort: <array | object | function>
|
|
1170
|
+
},
|
|
1171
|
+
},
|
|
1172
|
+
};
|
|
1173
|
+
`;
|
|
1174
|
+
if (isError)
|
|
1175
|
+
throw new Error(message);
|
|
1176
|
+
logger3.log(message);
|
|
1177
|
+
}, stripTSModifiers = (expr) => t4.isTSAsExpression(expr) || t4.isTSSatisfiesExpression(expr) ? expr.expression : expr, parseParameters = (params) => {
|
|
1178
|
+
let paramsObject = stripTSModifiers(params);
|
|
1179
|
+
if (t4.isObjectExpression(paramsObject)) {
|
|
1180
|
+
let options = getValue(paramsObject, "options");
|
|
1181
|
+
if (options) {
|
|
1182
|
+
if (t4.isObjectExpression(options))
|
|
1183
|
+
return getValue(options, "storySort");
|
|
1184
|
+
unsupported("options", !0);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
}, parseDefault = (defaultExpr, program) => {
|
|
1188
|
+
let defaultObj = stripTSModifiers(defaultExpr);
|
|
1189
|
+
if (t4.isObjectExpression(defaultObj)) {
|
|
1190
|
+
let params = getValue(defaultObj, "parameters");
|
|
1191
|
+
if (t4.isIdentifier(params) && (params = findVarInitialization(params.name, program)), params)
|
|
1192
|
+
return parseParameters(params);
|
|
1193
|
+
} else
|
|
1194
|
+
unsupported("default", !0);
|
|
1195
|
+
}, getStorySortParameter = (previewCode) => {
|
|
1196
|
+
if (!previewCode.includes("storySort"))
|
|
1197
|
+
return;
|
|
1198
|
+
let storySort, ast = babelParse3(previewCode);
|
|
1199
|
+
if (traverse3(ast, {
|
|
1200
|
+
ExportNamedDeclaration: {
|
|
1201
|
+
enter({ node }) {
|
|
1202
|
+
t4.isVariableDeclaration(node.declaration) ? node.declaration.declarations.forEach((decl) => {
|
|
1203
|
+
if (t4.isVariableDeclarator(decl) && t4.isIdentifier(decl.id)) {
|
|
1204
|
+
let { name: exportName } = decl.id;
|
|
1205
|
+
if (exportName === "parameters" && decl.init) {
|
|
1206
|
+
let paramsObject = stripTSModifiers(decl.init);
|
|
1207
|
+
storySort = parseParameters(paramsObject);
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}) : node.specifiers.forEach((spec) => {
|
|
1211
|
+
t4.isIdentifier(spec.exported) && spec.exported.name === "parameters" && unsupported("parameters", !1);
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
},
|
|
1215
|
+
ExportDefaultDeclaration: {
|
|
1216
|
+
enter({ node }) {
|
|
1217
|
+
let defaultObj = node.declaration;
|
|
1218
|
+
t4.isIdentifier(defaultObj) && (defaultObj = findVarInitialization(defaultObj.name, ast.program)), defaultObj = stripTSModifiers(defaultObj), t4.isCallExpression(defaultObj) && t4.isObjectExpression(defaultObj.arguments?.[0]) ? storySort = parseDefault(defaultObj.arguments[0], ast.program) : t4.isObjectExpression(defaultObj) ? storySort = parseDefault(defaultObj, ast.program) : unsupported("default", !1);
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
}), !!storySort) {
|
|
1222
|
+
if (t4.isArrowFunctionExpression(storySort)) {
|
|
1223
|
+
let { code: sortCode } = generate3(storySort, {});
|
|
1224
|
+
return (0, eval)(sortCode);
|
|
1225
|
+
}
|
|
1226
|
+
if (t4.isFunctionExpression(storySort)) {
|
|
1227
|
+
let { code: sortCode } = generate3(storySort, {}), functionName = storySort.id?.name, wrapper = `(a, b) => {
|
|
1228
|
+
${sortCode};
|
|
1229
|
+
return ${functionName}(a, b)
|
|
1230
|
+
}`;
|
|
1231
|
+
return (0, eval)(wrapper);
|
|
1232
|
+
}
|
|
1233
|
+
return t4.isLiteral(storySort) || t4.isArrayExpression(storySort) || t4.isObjectExpression(storySort) ? parseValue(storySort) : unsupported("storySort", !0);
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1236
|
+
|
|
1237
|
+
// src/csf-tools/enrichCsf.ts
|
|
1238
|
+
import { generate as generate4, types as t5 } from "storybook/internal/babel";
|
|
1239
|
+
var enrichCsfStory = (csf, csfSource, key, options) => {
|
|
1240
|
+
let storyExport = csfSource.getStoryExport(key), isCsfFactory = t5.isCallExpression(storyExport) && t5.isMemberExpression(storyExport.callee) && t5.isIdentifier(storyExport.callee.object) && storyExport.callee.object.name === "meta", source = !options?.disableSource && extractSource(storyExport), description = !options?.disableDescription && extractDescription(csfSource._storyStatements[key]), parameters = [], baseStoryObject = isCsfFactory ? t5.memberExpression(t5.identifier(key), t5.identifier("input")) : t5.identifier(key), originalParameters = t5.memberExpression(baseStoryObject, t5.identifier("parameters"));
|
|
1241
|
+
parameters.push(t5.spreadElement(originalParameters));
|
|
1242
|
+
let optionalDocs = t5.optionalMemberExpression(
|
|
1243
|
+
originalParameters,
|
|
1244
|
+
t5.identifier("docs"),
|
|
1245
|
+
!1,
|
|
1246
|
+
!0
|
|
1247
|
+
), extraDocsParameters = [];
|
|
1248
|
+
if (source) {
|
|
1249
|
+
let optionalSource = t5.optionalMemberExpression(
|
|
1250
|
+
optionalDocs,
|
|
1251
|
+
t5.identifier("source"),
|
|
1252
|
+
!1,
|
|
1253
|
+
!0
|
|
1254
|
+
);
|
|
1255
|
+
extraDocsParameters.push(
|
|
1256
|
+
t5.objectProperty(
|
|
1257
|
+
t5.identifier("source"),
|
|
1258
|
+
t5.objectExpression([
|
|
1259
|
+
t5.objectProperty(t5.identifier("originalSource"), t5.stringLiteral(source)),
|
|
1260
|
+
t5.spreadElement(optionalSource)
|
|
1261
|
+
])
|
|
1262
|
+
)
|
|
1263
|
+
);
|
|
1264
|
+
}
|
|
1265
|
+
if (description) {
|
|
1266
|
+
let optionalDescription = t5.optionalMemberExpression(
|
|
1267
|
+
optionalDocs,
|
|
1268
|
+
t5.identifier("description"),
|
|
1269
|
+
!1,
|
|
1270
|
+
!0
|
|
1271
|
+
);
|
|
1272
|
+
extraDocsParameters.push(
|
|
1273
|
+
t5.objectProperty(
|
|
1274
|
+
t5.identifier("description"),
|
|
1275
|
+
t5.objectExpression([
|
|
1276
|
+
t5.objectProperty(t5.identifier("story"), t5.stringLiteral(description)),
|
|
1277
|
+
t5.spreadElement(optionalDescription)
|
|
1278
|
+
])
|
|
1279
|
+
)
|
|
1280
|
+
);
|
|
1281
|
+
}
|
|
1282
|
+
if (extraDocsParameters.length > 0) {
|
|
1283
|
+
parameters.push(
|
|
1284
|
+
t5.objectProperty(
|
|
1285
|
+
t5.identifier("docs"),
|
|
1286
|
+
t5.objectExpression([t5.spreadElement(optionalDocs), ...extraDocsParameters])
|
|
1287
|
+
)
|
|
1288
|
+
);
|
|
1289
|
+
let addParameter = t5.expressionStatement(
|
|
1290
|
+
t5.assignmentExpression("=", originalParameters, t5.objectExpression(parameters))
|
|
1291
|
+
);
|
|
1292
|
+
csf._ast.program.body.push(addParameter);
|
|
1293
|
+
}
|
|
1294
|
+
}, addComponentDescription = (node, path, value) => {
|
|
1295
|
+
if (!path.length) {
|
|
1296
|
+
node.properties.find(
|
|
1297
|
+
(p) => t5.isObjectProperty(p) && t5.isIdentifier(p.key) && p.key.name === "component"
|
|
1298
|
+
) || node.properties.unshift(value);
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
let [first, ...rest] = path, existing = node.properties.find(
|
|
1302
|
+
(p) => t5.isObjectProperty(p) && t5.isIdentifier(p.key) && p.key.name === first && t5.isObjectExpression(p.value)
|
|
1303
|
+
), subNode;
|
|
1304
|
+
existing ? subNode = existing.value : (subNode = t5.objectExpression([]), node.properties.push(t5.objectProperty(t5.identifier(first), subNode))), addComponentDescription(subNode, rest, value);
|
|
1305
|
+
}, enrichCsfMeta = (csf, csfSource, options) => {
|
|
1306
|
+
let description = !options?.disableDescription && extractDescription(csfSource._metaStatement);
|
|
1307
|
+
if (description) {
|
|
1308
|
+
let metaNode = csf._metaNode;
|
|
1309
|
+
metaNode && t5.isObjectExpression(metaNode) && addComponentDescription(
|
|
1310
|
+
metaNode,
|
|
1311
|
+
["parameters", "docs", "description"],
|
|
1312
|
+
t5.objectProperty(t5.identifier("component"), t5.stringLiteral(description))
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
}, enrichCsf = async (csf, csfSource, options) => {
|
|
1316
|
+
enrichCsfMeta(csf, csfSource, options), await options?.enrichCsf?.(csf, csfSource), Object.keys(csf._storyExports).forEach((key) => {
|
|
1317
|
+
enrichCsfStory(csf, csfSource, key, options);
|
|
1318
|
+
});
|
|
1319
|
+
}, extractSource = (node) => {
|
|
1320
|
+
let src = t5.isVariableDeclarator(node) ? node.init : node, { code } = generate4(src, {});
|
|
1321
|
+
return code;
|
|
1322
|
+
}, extractDescription = (node) => node?.leadingComments ? node.leadingComments.map((comment) => comment.type === "CommentLine" || !comment.value.startsWith("*") ? null : comment.value.split(`
|
|
1323
|
+
`).map((line) => line.replace(/^(\s+)?(\*+)?(\s)?/, "")).join(`
|
|
1324
|
+
`).trim()).filter(Boolean).join(`
|
|
1325
|
+
`) : "";
|
|
1326
|
+
|
|
1327
|
+
// src/csf-tools/index.ts
|
|
1328
|
+
import { babelParse as babelParse4 } from "storybook/internal/babel";
|
|
1329
|
+
|
|
1330
|
+
// src/csf-tools/vitest-plugin/transformer.ts
|
|
1331
|
+
var import_ts_dedent4 = __toESM(require_dist(), 1);
|
|
1332
|
+
import { types as t6 } from "storybook/internal/babel";
|
|
1333
|
+
import { getStoryTitle } from "storybook/internal/common";
|
|
1334
|
+
import { combineTags } from "storybook/internal/csf";
|
|
1335
|
+
import { logger as logger4 } from "storybook/internal/node-logger";
|
|
1336
|
+
var isValidTest = (storyTags, tagsFilter) => !(tagsFilter.include.length && !tagsFilter.include.some((tag) => storyTags?.includes(tag)) || tagsFilter.exclude.some((tag) => storyTags?.includes(tag))), DOUBLE_SPACES = " ", getLiteralWithZeroWidthSpace = (testTitle) => t6.stringLiteral(`${testTitle}${DOUBLE_SPACES}`);
|
|
1337
|
+
async function vitestTransform({
|
|
1338
|
+
code,
|
|
1339
|
+
fileName,
|
|
1340
|
+
configDir,
|
|
1341
|
+
stories,
|
|
1342
|
+
tagsFilter,
|
|
1343
|
+
previewLevelTags = []
|
|
1344
|
+
}) {
|
|
1345
|
+
let parsed = loadCsf(code, {
|
|
1346
|
+
fileName,
|
|
1347
|
+
transformInlineMeta: !0,
|
|
1348
|
+
makeTitle: (title) => {
|
|
1349
|
+
let result = getStoryTitle({
|
|
1350
|
+
storyFilePath: fileName,
|
|
1351
|
+
configDir,
|
|
1352
|
+
stories,
|
|
1353
|
+
userTitle: title
|
|
1354
|
+
}) || "unknown";
|
|
1355
|
+
return result === "unknown" && logger4.warn(
|
|
1356
|
+
import_ts_dedent4.dedent`
|
|
1357
|
+
[Storybook]: Could not calculate story title for "${fileName}".
|
|
1358
|
+
Please make sure that this file matches the globs included in the "stories" field in your Storybook configuration at "${configDir}".
|
|
1359
|
+
`
|
|
1360
|
+
), result;
|
|
1361
|
+
}
|
|
1362
|
+
}).parse(), ast = parsed._ast, metaExportName = parsed._metaVariableName, metaNode = parsed._metaNode, metaTitleProperty = metaNode.properties.find(
|
|
1363
|
+
(prop) => t6.isObjectProperty(prop) && t6.isIdentifier(prop.key) && prop.key.name === "title"
|
|
1364
|
+
), metaTitle = t6.stringLiteral(parsed._meta?.title || "unknown");
|
|
1365
|
+
if (metaTitleProperty ? t6.isObjectProperty(metaTitleProperty) && (metaTitleProperty.value = metaTitle) : metaNode.properties.push(t6.objectProperty(t6.identifier("title"), metaTitle)), !metaNode || !parsed._meta)
|
|
1366
|
+
throw new Error(
|
|
1367
|
+
`The Storybook vitest plugin could not detect the meta (default export) object in the story file.
|
|
1368
|
+
|
|
1369
|
+
Please make sure you have a default export with the meta object. If you are using a different export format that is not supported, please file an issue with details about your use case.`
|
|
1370
|
+
);
|
|
1371
|
+
let validStories = {};
|
|
1372
|
+
Object.keys(parsed._stories).forEach((key) => {
|
|
1373
|
+
let finalTags = combineTags(
|
|
1374
|
+
"test",
|
|
1375
|
+
"dev",
|
|
1376
|
+
...previewLevelTags,
|
|
1377
|
+
...parsed.meta?.tags || [],
|
|
1378
|
+
...parsed._stories[key].tags || []
|
|
1379
|
+
);
|
|
1380
|
+
isValidTest(finalTags, tagsFilter) && (validStories[key] = parsed._storyStatements[key]);
|
|
1381
|
+
});
|
|
1382
|
+
let vitestTestId = parsed._file.path.scope.generateUidIdentifier("test"), vitestDescribeId = parsed._file.path.scope.generateUidIdentifier("describe");
|
|
1383
|
+
if (Object.keys(validStories).length === 0) {
|
|
1384
|
+
let describeSkipBlock = t6.expressionStatement(
|
|
1385
|
+
t6.callExpression(t6.memberExpression(vitestDescribeId, t6.identifier("skip")), [
|
|
1386
|
+
t6.stringLiteral("No valid tests found")
|
|
1387
|
+
])
|
|
1388
|
+
);
|
|
1389
|
+
ast.program.body.push(describeSkipBlock);
|
|
1390
|
+
let imports2 = [
|
|
1391
|
+
t6.importDeclaration(
|
|
1392
|
+
[
|
|
1393
|
+
t6.importSpecifier(vitestTestId, t6.identifier("test")),
|
|
1394
|
+
t6.importSpecifier(vitestDescribeId, t6.identifier("describe"))
|
|
1395
|
+
],
|
|
1396
|
+
t6.stringLiteral("vitest")
|
|
1397
|
+
)
|
|
1398
|
+
];
|
|
1399
|
+
return ast.program.body.unshift(...imports2), formatCsf(parsed, { sourceMaps: !0, sourceFileName: fileName }, code);
|
|
1400
|
+
}
|
|
1401
|
+
let vitestExpectId = parsed._file.path.scope.generateUidIdentifier("expect"), testStoryId = parsed._file.path.scope.generateUidIdentifier("testStory"), skipTagsId = t6.identifier(JSON.stringify(tagsFilter.skip));
|
|
1402
|
+
function getTestGuardDeclaration() {
|
|
1403
|
+
let isRunningFromThisFileId2 = parsed._file.path.scope.generateUidIdentifier("isRunningFromThisFile"), testPathProperty = t6.memberExpression(
|
|
1404
|
+
t6.callExpression(t6.memberExpression(vitestExpectId, t6.identifier("getState")), []),
|
|
1405
|
+
t6.identifier("testPath")
|
|
1406
|
+
), filePathProperty = t6.memberExpression(
|
|
1407
|
+
t6.memberExpression(t6.identifier("globalThis"), t6.identifier("__vitest_worker__")),
|
|
1408
|
+
t6.identifier("filepath")
|
|
1409
|
+
), nullishCoalescingExpression = t6.logicalExpression(
|
|
1410
|
+
"??",
|
|
1411
|
+
// TODO: switch order of testPathProperty and filePathProperty when the bug is fixed
|
|
1412
|
+
// https://github.com/vitest-dev/vitest/issues/6367 (or probably just use testPathProperty)
|
|
1413
|
+
filePathProperty,
|
|
1414
|
+
testPathProperty
|
|
1415
|
+
), includesCall = t6.callExpression(
|
|
1416
|
+
t6.memberExpression(
|
|
1417
|
+
t6.callExpression(t6.identifier("convertToFilePath"), [
|
|
1418
|
+
t6.memberExpression(
|
|
1419
|
+
t6.memberExpression(t6.identifier("import"), t6.identifier("meta")),
|
|
1420
|
+
t6.identifier("url")
|
|
1421
|
+
)
|
|
1422
|
+
]),
|
|
1423
|
+
t6.identifier("includes")
|
|
1424
|
+
),
|
|
1425
|
+
[nullishCoalescingExpression]
|
|
1426
|
+
);
|
|
1427
|
+
return { isRunningFromThisFileDeclaration: t6.variableDeclaration("const", [
|
|
1428
|
+
t6.variableDeclarator(isRunningFromThisFileId2, includesCall)
|
|
1429
|
+
]), isRunningFromThisFileId: isRunningFromThisFileId2 };
|
|
1430
|
+
}
|
|
1431
|
+
let { isRunningFromThisFileDeclaration, isRunningFromThisFileId } = getTestGuardDeclaration();
|
|
1432
|
+
ast.program.body.push(isRunningFromThisFileDeclaration);
|
|
1433
|
+
let getTestStatementForStory = ({
|
|
1434
|
+
localName,
|
|
1435
|
+
exportName,
|
|
1436
|
+
testTitle,
|
|
1437
|
+
node,
|
|
1438
|
+
overrideSourcemap = !0,
|
|
1439
|
+
storyId
|
|
1440
|
+
}) => {
|
|
1441
|
+
let testStoryCall = t6.expressionStatement(
|
|
1442
|
+
t6.callExpression(vitestTestId, [
|
|
1443
|
+
t6.stringLiteral(testTitle),
|
|
1444
|
+
t6.callExpression(testStoryId, [
|
|
1445
|
+
t6.stringLiteral(exportName),
|
|
1446
|
+
t6.identifier(localName),
|
|
1447
|
+
t6.identifier(metaExportName),
|
|
1448
|
+
skipTagsId,
|
|
1449
|
+
t6.stringLiteral(storyId)
|
|
1450
|
+
])
|
|
1451
|
+
])
|
|
1452
|
+
);
|
|
1453
|
+
return overrideSourcemap && (testStoryCall.loc = node.loc), testStoryCall;
|
|
1454
|
+
}, getDescribeStatementForStory = (options) => {
|
|
1455
|
+
let { localName, describeTitle, exportName, tests, node, parentStoryId } = options, describeBlock = t6.callExpression(vitestDescribeId, [
|
|
1456
|
+
getLiteralWithZeroWidthSpace(describeTitle),
|
|
1457
|
+
t6.arrowFunctionExpression(
|
|
1458
|
+
[],
|
|
1459
|
+
t6.blockStatement([
|
|
1460
|
+
getTestStatementForStory({
|
|
1461
|
+
...options,
|
|
1462
|
+
testTitle: "base story",
|
|
1463
|
+
overrideSourcemap: !1,
|
|
1464
|
+
storyId: parentStoryId
|
|
1465
|
+
}),
|
|
1466
|
+
...tests.map(({ name: testName, node: testNode, id: storyId }) => {
|
|
1467
|
+
let testStatement = t6.expressionStatement(
|
|
1468
|
+
t6.callExpression(vitestTestId, [
|
|
1469
|
+
t6.stringLiteral(testName),
|
|
1470
|
+
t6.callExpression(testStoryId, [
|
|
1471
|
+
t6.stringLiteral(exportName),
|
|
1472
|
+
t6.identifier(localName),
|
|
1473
|
+
t6.identifier(metaExportName),
|
|
1474
|
+
t6.arrayExpression([]),
|
|
1475
|
+
t6.stringLiteral(storyId),
|
|
1476
|
+
t6.stringLiteral(testName)
|
|
1477
|
+
])
|
|
1478
|
+
])
|
|
1479
|
+
);
|
|
1480
|
+
return testStatement.loc = testNode.loc, testStatement;
|
|
1481
|
+
})
|
|
1482
|
+
])
|
|
1483
|
+
)
|
|
1484
|
+
]);
|
|
1485
|
+
return describeBlock.loc = node.loc, t6.expressionStatement(describeBlock);
|
|
1486
|
+
}, storyTestStatements = Object.entries(validStories).map(([exportName, node]) => {
|
|
1487
|
+
if (node === null) {
|
|
1488
|
+
logger4.warn(
|
|
1489
|
+
import_ts_dedent4.dedent`
|
|
1490
|
+
[Storybook]: Could not transform "${exportName}" story into test at "${fileName}".
|
|
1491
|
+
Please make sure to define stories in the same file and not re-export stories coming from other files".
|
|
1492
|
+
`
|
|
1493
|
+
);
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
let localName = parsed._stories[exportName].localName ?? exportName, testTitle = parsed._stories[exportName].name ?? exportName, storyId = parsed._stories[exportName].id, tests = parsed.getStoryTests(exportName);
|
|
1497
|
+
return tests?.length > 0 ? getDescribeStatementForStory({
|
|
1498
|
+
localName,
|
|
1499
|
+
describeTitle: testTitle,
|
|
1500
|
+
exportName,
|
|
1501
|
+
tests,
|
|
1502
|
+
node,
|
|
1503
|
+
parentStoryId: storyId
|
|
1504
|
+
}) : getTestStatementForStory({
|
|
1505
|
+
testTitle,
|
|
1506
|
+
localName,
|
|
1507
|
+
exportName,
|
|
1508
|
+
node,
|
|
1509
|
+
storyId
|
|
1510
|
+
});
|
|
1511
|
+
}).filter((st) => !!st), testBlock = t6.ifStatement(isRunningFromThisFileId, t6.blockStatement(storyTestStatements));
|
|
1512
|
+
ast.program.body.push(testBlock);
|
|
1513
|
+
let hasTests = Object.keys(validStories).some(
|
|
1514
|
+
(exportName) => parsed.getStoryTests(exportName).length > 0
|
|
1515
|
+
), imports = [
|
|
1516
|
+
t6.importDeclaration(
|
|
1517
|
+
[
|
|
1518
|
+
t6.importSpecifier(vitestTestId, t6.identifier("test")),
|
|
1519
|
+
t6.importSpecifier(vitestExpectId, t6.identifier("expect")),
|
|
1520
|
+
...hasTests ? [t6.importSpecifier(vitestDescribeId, t6.identifier("describe"))] : []
|
|
1521
|
+
],
|
|
1522
|
+
t6.stringLiteral("vitest")
|
|
1523
|
+
),
|
|
1524
|
+
t6.importDeclaration(
|
|
1525
|
+
[
|
|
1526
|
+
t6.importSpecifier(testStoryId, t6.identifier("testStory")),
|
|
1527
|
+
t6.importSpecifier(t6.identifier("convertToFilePath"), t6.identifier("convertToFilePath"))
|
|
1528
|
+
],
|
|
1529
|
+
t6.stringLiteral("@storybook/addon-vitest/internal/test-utils")
|
|
1530
|
+
)
|
|
1531
|
+
];
|
|
1532
|
+
return ast.program.body.unshift(...imports), formatCsf(parsed, { sourceMaps: !0, sourceFileName: fileName }, code);
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
export {
|
|
1536
|
+
isValidPreviewPath,
|
|
1537
|
+
isModuleMock,
|
|
1538
|
+
NoMetaError,
|
|
1539
|
+
MultipleMetaError,
|
|
1540
|
+
MixedFactoryError,
|
|
1541
|
+
BadMetaError,
|
|
1542
|
+
CsfFile,
|
|
1543
|
+
babelParseFile,
|
|
1544
|
+
loadCsf,
|
|
1545
|
+
formatCsf,
|
|
1546
|
+
printCsf,
|
|
1547
|
+
readCsf,
|
|
1548
|
+
writeCsf,
|
|
1549
|
+
ConfigFile,
|
|
1550
|
+
loadConfig,
|
|
1551
|
+
formatConfig,
|
|
1552
|
+
printConfig,
|
|
1553
|
+
readConfig,
|
|
1554
|
+
writeConfig,
|
|
1555
|
+
isCsfFactoryPreview,
|
|
1556
|
+
getStorySortParameter,
|
|
1557
|
+
enrichCsfStory,
|
|
1558
|
+
enrichCsfMeta,
|
|
1559
|
+
enrichCsf,
|
|
1560
|
+
extractSource,
|
|
1561
|
+
extractDescription,
|
|
1562
|
+
vitestTransform,
|
|
1563
|
+
babelParse4 as babelParse
|
|
1564
|
+
};
|