1 | function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
2 |
|
3 | import deprecate from 'util-deprecate';
|
4 | import dedent from 'ts-dedent';
|
5 | import global from 'global';
|
6 | import { logger } from '@storybook/client-logger';
|
7 | import { toId, sanitize } from '@storybook/csf';
|
8 | import { combineParameters, normalizeInputTypes } from '@storybook/store';
|
9 | import { StoryStoreFacade } from './StoryStoreFacade';
|
10 |
|
11 |
|
12 | let singleton;
|
13 | const warningAlternatives = {
|
14 | addDecorator: `Instead, use \`export const decorators = [];\` in your \`preview.js\`.`,
|
15 | addParameters: `Instead, use \`export const parameters = {};\` in your \`preview.js\`.`,
|
16 | addLoaders: `Instead, use \`export const loaders = [];\` in your \`preview.js\`.`
|
17 | };
|
18 |
|
19 | const warningMessage = method => deprecate(() => {}, dedent`
|
20 | \`${method}\` is deprecated, and will be removed in Storybook 7.0.
|
21 |
|
22 | ${warningAlternatives[method]}
|
23 |
|
24 | Read more at https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-addparameters-and-adddecorator).`);
|
25 |
|
26 | const warnings = {
|
27 | addDecorator: warningMessage('addDecorator'),
|
28 | addParameters: warningMessage('addParameters'),
|
29 | addLoaders: warningMessage('addLoaders')
|
30 | };
|
31 |
|
32 | const checkMethod = (method, deprecationWarning) => {
|
33 | var _global$FEATURES;
|
34 |
|
35 | if ((_global$FEATURES = global.FEATURES) !== null && _global$FEATURES !== void 0 && _global$FEATURES.storyStoreV7) {
|
36 | throw new Error(dedent`You cannot use \`${method}\` with the new Story Store.
|
37 |
|
38 | ${warningAlternatives[method]}`);
|
39 | }
|
40 |
|
41 | if (!singleton) {
|
42 | throw new Error(`Singleton client API not yet initialized, cannot call \`${method}\`.`);
|
43 | }
|
44 |
|
45 | if (deprecationWarning) {
|
46 | warnings[method]();
|
47 | }
|
48 | };
|
49 |
|
50 | export const addDecorator = (decorator, deprecationWarning = true) => {
|
51 | checkMethod('addDecorator', deprecationWarning);
|
52 | singleton.addDecorator(decorator);
|
53 | };
|
54 | export const addParameters = (parameters, deprecationWarning = true) => {
|
55 | checkMethod('addParameters', deprecationWarning);
|
56 | singleton.addParameters(parameters);
|
57 | };
|
58 | export const addLoader = (loader, deprecationWarning = true) => {
|
59 | checkMethod('addLoader', deprecationWarning);
|
60 | singleton.addLoader(loader);
|
61 | };
|
62 | export const addArgsEnhancer = enhancer => {
|
63 | checkMethod('addArgsEnhancer', false);
|
64 | singleton.addArgsEnhancer(enhancer);
|
65 | };
|
66 | export const addArgTypesEnhancer = enhancer => {
|
67 | checkMethod('addArgTypesEnhancer', false);
|
68 | singleton.addArgTypesEnhancer(enhancer);
|
69 | };
|
70 | export const getGlobalRender = () => {
|
71 | checkMethod('getGlobalRender', false);
|
72 | return singleton.facade.projectAnnotations.render;
|
73 | };
|
74 | export const setGlobalRender = render => {
|
75 | checkMethod('setGlobalRender', false);
|
76 | singleton.facade.projectAnnotations.render = render;
|
77 | };
|
78 | const invalidStoryTypes = new Set(['string', 'number', 'boolean', 'symbol']);
|
79 | export class ClientApi {
|
80 |
|
81 |
|
82 | constructor({
|
83 | storyStore
|
84 | } = {}) {
|
85 | this.facade = void 0;
|
86 | this.storyStore = void 0;
|
87 | this.addons = void 0;
|
88 | this.onImportFnChanged = void 0;
|
89 | this.lastFileName = 0;
|
90 | this.setAddon = deprecate(addon => {
|
91 | this.addons = Object.assign({}, this.addons, addon);
|
92 | }, dedent`
|
93 | \`setAddon\` is deprecated and will be removed in Storybook 7.0.
|
94 |
|
95 | https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-setaddon
|
96 | `);
|
97 |
|
98 | this.addDecorator = decorator => {
|
99 | this.facade.projectAnnotations.decorators.push(decorator);
|
100 | };
|
101 |
|
102 | this.clearDecorators = deprecate(() => {
|
103 | this.facade.projectAnnotations.decorators = [];
|
104 | }, dedent`
|
105 | \`clearDecorators\` is deprecated and will be removed in Storybook 7.0.
|
106 |
|
107 | https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-cleardecorators
|
108 | `);
|
109 |
|
110 | this.addParameters = (_ref) => {
|
111 | let {
|
112 | globals,
|
113 | globalTypes
|
114 | } = _ref,
|
115 | parameters = _objectWithoutPropertiesLoose(_ref, ["globals", "globalTypes"]);
|
116 |
|
117 | this.facade.projectAnnotations.parameters = combineParameters(this.facade.projectAnnotations.parameters, parameters);
|
118 |
|
119 | if (globals) {
|
120 | this.facade.projectAnnotations.globals = Object.assign({}, this.facade.projectAnnotations.globals, globals);
|
121 | }
|
122 |
|
123 | if (globalTypes) {
|
124 | this.facade.projectAnnotations.globalTypes = Object.assign({}, this.facade.projectAnnotations.globalTypes, normalizeInputTypes(globalTypes));
|
125 | }
|
126 | };
|
127 |
|
128 | this.addLoader = loader => {
|
129 | this.facade.projectAnnotations.loaders.push(loader);
|
130 | };
|
131 |
|
132 | this.addArgsEnhancer = enhancer => {
|
133 | this.facade.projectAnnotations.argsEnhancers.push(enhancer);
|
134 | };
|
135 |
|
136 | this.addArgTypesEnhancer = enhancer => {
|
137 | this.facade.projectAnnotations.argTypesEnhancers.push(enhancer);
|
138 | };
|
139 |
|
140 | this.storiesOf = (kind, m) => {
|
141 | if (!kind && typeof kind !== 'string') {
|
142 | throw new Error('Invalid or missing kind provided for stories, should be a string');
|
143 | }
|
144 |
|
145 | if (!m) {
|
146 | logger.warn(`Missing 'module' parameter for story with a kind of '${kind}'. It will break your HMR`);
|
147 | }
|
148 |
|
149 | if (m) {
|
150 | const proto = Object.getPrototypeOf(m);
|
151 |
|
152 | if (proto.exports && proto.exports.default) {
|
153 |
|
154 | logger.error(`Illegal mix of CSF default export and storiesOf calls in a single file: ${proto.i}`);
|
155 | }
|
156 | }
|
157 |
|
158 |
|
159 | const baseFilename = m && m.id ? `${m.id}` : (this.lastFileName++).toString();
|
160 | let fileName = baseFilename;
|
161 | let i = 1;
|
162 |
|
163 |
|
164 |
|
165 | while (this.facade.csfExports[fileName] && Object.keys(this.facade.csfExports[fileName]).length > 0) {
|
166 | i += 1;
|
167 | fileName = `${baseFilename}-${i}`;
|
168 | }
|
169 |
|
170 | if (m && m.hot && m.hot.accept) {
|
171 |
|
172 |
|
173 | m.hot.accept();
|
174 | m.hot.dispose(() => {
|
175 | this.facade.clearFilenameExports(fileName);
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 | setTimeout(() => {
|
182 | var _this$onImportFnChang;
|
183 |
|
184 | (_this$onImportFnChang = this.onImportFnChanged) === null || _this$onImportFnChang === void 0 ? void 0 : _this$onImportFnChang.call(this, {
|
185 | importFn: this.importFn.bind(this)
|
186 | });
|
187 | }, 0);
|
188 | });
|
189 | }
|
190 |
|
191 | let hasAdded = false;
|
192 | const api = {
|
193 | kind: kind.toString(),
|
194 | add: () => api,
|
195 | addDecorator: () => api,
|
196 | addLoader: () => api,
|
197 | addParameters: () => api
|
198 | };
|
199 |
|
200 | Object.keys(this.addons).forEach(name => {
|
201 | const addon = this.addons[name];
|
202 |
|
203 | api[name] = (...args) => {
|
204 | addon.apply(api, args);
|
205 | return api;
|
206 | };
|
207 | });
|
208 | const meta = {
|
209 | id: sanitize(kind),
|
210 | title: kind,
|
211 | decorators: [],
|
212 | loaders: [],
|
213 | parameters: {}
|
214 | };
|
215 |
|
216 | this.facade.csfExports[fileName] = {
|
217 | default: meta
|
218 | };
|
219 | let counter = 0;
|
220 |
|
221 | api.add = (storyName, storyFn, parameters = {}) => {
|
222 | hasAdded = true;
|
223 |
|
224 | if (typeof storyName !== 'string') {
|
225 | throw new Error(`Invalid or missing storyName provided for a "${kind}" story.`);
|
226 | }
|
227 |
|
228 | if (!storyFn || Array.isArray(storyFn) || invalidStoryTypes.has(typeof storyFn)) {
|
229 | throw new Error(`Cannot load story "${storyName}" in "${kind}" due to invalid format. Storybook expected a function/object but received ${typeof storyFn} instead.`);
|
230 | }
|
231 |
|
232 | const {
|
233 | decorators,
|
234 | loaders,
|
235 | component,
|
236 | args,
|
237 | argTypes
|
238 | } = parameters,
|
239 | storyParameters = _objectWithoutPropertiesLoose(parameters, ["decorators", "loaders", "component", "args", "argTypes"]);
|
240 |
|
241 |
|
242 | const storyId = parameters.__id || toId(kind, storyName);
|
243 | const csfExports = this.facade.csfExports[fileName];
|
244 |
|
245 | csfExports[`story${counter}`] = {
|
246 | name: storyName,
|
247 | parameters: Object.assign({
|
248 | fileName,
|
249 | __id: storyId
|
250 | }, storyParameters),
|
251 | decorators,
|
252 | loaders,
|
253 | args,
|
254 | argTypes,
|
255 | component,
|
256 | render: storyFn
|
257 | };
|
258 | counter += 1;
|
259 | this.facade.stories[storyId] = {
|
260 | id: storyId,
|
261 | title: csfExports.default.title,
|
262 | name: storyName,
|
263 | importPath: fileName
|
264 | };
|
265 | return api;
|
266 | };
|
267 |
|
268 | api.addDecorator = decorator => {
|
269 | if (hasAdded) throw new Error(`You cannot add a decorator after the first story for a kind.
|
270 | Read more here: https://github.com/storybookjs/storybook/blob/master/MIGRATION.md#can-no-longer-add-decoratorsparameters-after-stories`);
|
271 | meta.decorators.push(decorator);
|
272 | return api;
|
273 | };
|
274 |
|
275 | api.addLoader = loader => {
|
276 | if (hasAdded) throw new Error(`You cannot add a loader after the first story for a kind.`);
|
277 | meta.loaders.push(loader);
|
278 | return api;
|
279 | };
|
280 |
|
281 | api.addParameters = (_ref2) => {
|
282 | let {
|
283 | component,
|
284 | args,
|
285 | argTypes
|
286 | } = _ref2,
|
287 | parameters = _objectWithoutPropertiesLoose(_ref2, ["component", "args", "argTypes"]);
|
288 |
|
289 | if (hasAdded) throw new Error(`You cannot add parameters after the first story for a kind.
|
290 | Read more here: https://github.com/storybookjs/storybook/blob/master/MIGRATION.md#can-no-longer-add-decoratorsparameters-after-stories`);
|
291 | meta.parameters = combineParameters(meta.parameters, parameters);
|
292 | if (component) meta.component = component;
|
293 | if (args) meta.args = Object.assign({}, meta.args, args);
|
294 | if (argTypes) meta.argTypes = Object.assign({}, meta.argTypes, argTypes);
|
295 | return api;
|
296 | };
|
297 |
|
298 | return api;
|
299 | };
|
300 |
|
301 | this.getStorybook = () => {
|
302 | const {
|
303 | stories
|
304 | } = this.storyStore.storyIndex;
|
305 | const kinds = {};
|
306 | Object.entries(stories).forEach(([storyId, {
|
307 | title,
|
308 | name,
|
309 | importPath
|
310 | }]) => {
|
311 | if (!kinds[title]) {
|
312 | kinds[title] = {
|
313 | kind: title,
|
314 | fileName: importPath,
|
315 | stories: []
|
316 | };
|
317 | }
|
318 |
|
319 | const {
|
320 | storyFn
|
321 | } = this.storyStore.fromId(storyId);
|
322 | kinds[title].stories.push({
|
323 | name,
|
324 | render: storyFn
|
325 | });
|
326 | });
|
327 | return Object.values(kinds);
|
328 | };
|
329 |
|
330 | this.raw = () => {
|
331 | return this.storyStore.raw();
|
332 | };
|
333 |
|
334 | this.facade = new StoryStoreFacade();
|
335 | this.addons = {};
|
336 | this.storyStore = storyStore;
|
337 | singleton = this;
|
338 | }
|
339 |
|
340 | importFn(path) {
|
341 | return this.facade.importFn(path);
|
342 | }
|
343 |
|
344 | getStoryIndex() {
|
345 | if (!this.storyStore) {
|
346 | throw new Error('Cannot get story index before setting storyStore');
|
347 | }
|
348 |
|
349 | return this.facade.getStoryIndex(this.storyStore);
|
350 | }
|
351 |
|
352 |
|
353 | get _storyStore() {
|
354 | return this.storyStore;
|
355 | }
|
356 |
|
357 | } |
\ | No newline at end of file |