UNPKG

6.43 kBJavaScriptView Raw
1function _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
3import "core-js/modules/es.array.reduce.js";
4import global from 'global';
5import dedent from 'ts-dedent';
6import { SynchronousPromise } from 'synchronous-promise';
7import { toId, isExportStory, storyNameFromExport } from '@storybook/csf';
8import { autoTitle, sortStoriesV6 } from '@storybook/store';
9import { logger } from '@storybook/client-logger';
10export class StoryStoreFacade {
11 constructor() {
12 this.projectAnnotations = void 0;
13 this.stories = void 0;
14 this.csfExports = void 0;
15 this.projectAnnotations = {
16 loaders: [],
17 decorators: [],
18 parameters: {},
19 argsEnhancers: [],
20 argTypesEnhancers: []
21 };
22 this.stories = {};
23 this.csfExports = {};
24 } // This doesn't actually import anything because the client-api loads fully
25 // on startup, but this is a shim after all.
26
27
28 importFn(path) {
29 return SynchronousPromise.resolve().then(() => {
30 const moduleExports = this.csfExports[path];
31 if (!moduleExports) throw new Error(`Unknown path: ${path}`);
32 return moduleExports;
33 });
34 }
35
36 getStoryIndex(store) {
37 var _this$projectAnnotati, _this$projectAnnotati2;
38
39 const fileNameOrder = Object.keys(this.csfExports);
40 const storySortParameter = (_this$projectAnnotati = this.projectAnnotations.parameters) === null || _this$projectAnnotati === void 0 ? void 0 : (_this$projectAnnotati2 = _this$projectAnnotati.options) === null || _this$projectAnnotati2 === void 0 ? void 0 : _this$projectAnnotati2.storySort;
41 const storyEntries = Object.entries(this.stories); // Add the kind parameters and global parameters to each entry
42
43 const sortableV6 = storyEntries.map(([storyId, {
44 importPath
45 }]) => {
46 const exports = this.csfExports[importPath];
47 const csfFile = store.processCSFFileWithCache(exports, importPath, exports.default.title);
48 return [storyId, store.storyFromCSFFile({
49 storyId,
50 csfFile
51 }), csfFile.meta.parameters, this.projectAnnotations.parameters];
52 }); // NOTE: the sortStoriesV6 version returns the v7 data format. confusing but more convenient!
53
54 let sortedV7;
55
56 try {
57 sortedV7 = sortStoriesV6(sortableV6, storySortParameter, fileNameOrder);
58 } catch (err) {
59 if (typeof storySortParameter === 'function') {
60 throw new Error(dedent`
61 Error sorting stories with sort parameter ${storySortParameter}:
62
63 > ${err.message}
64
65 Are you using a V7-style sort function in V6 compatibility mode?
66
67 More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#v7-style-story-sort
68 `);
69 }
70
71 throw err;
72 }
73
74 const stories = sortedV7.reduce((acc, s) => {
75 // We use the original entry we stored in `this.stories` because it is possible that the CSF file itself
76 // exports a `parameters.fileName` which can be different and mess up our `importFn`.
77 // In fact, in Storyshots there is a Jest transformer that does exactly that.
78 // NOTE: this doesn't actually change the story object, just the index.
79 acc[s.id] = this.stories[s.id];
80 return acc;
81 }, {});
82 return {
83 v: 3,
84 stories
85 };
86 }
87
88 clearFilenameExports(fileName) {
89 if (!this.csfExports[fileName]) {
90 return;
91 } // Clear this module's stories from the storyList and existing exports
92
93
94 Object.entries(this.stories).forEach(([id, {
95 importPath
96 }]) => {
97 if (importPath === fileName) {
98 delete this.stories[id];
99 }
100 }); // We keep this as an empty record so we can use it to maintain component order
101
102 this.csfExports[fileName] = {};
103 } // NOTE: we could potentially share some of this code with the stories.json generation
104
105
106 addStoriesFromExports(fileName, fileExports) {
107 // if the export haven't changed since last time we added them, this is a no-op
108 if (this.csfExports[fileName] === fileExports) {
109 return;
110 } // OTOH, if they have changed, let's clear them out first
111
112
113 this.clearFilenameExports(fileName);
114
115 const {
116 default: defaultExport,
117 __namedExportsOrder
118 } = fileExports,
119 namedExports = _objectWithoutPropertiesLoose(fileExports, ["default", "__namedExportsOrder"]); // eslint-disable-next-line prefer-const
120
121
122 let {
123 id: componentId,
124 title
125 } = defaultExport || {};
126 title = title || autoTitle(fileName, (global.STORIES || []).map(specifier => Object.assign({}, specifier, {
127 importPathMatcher: new RegExp(specifier.importPathMatcher)
128 })));
129
130 if (!title) {
131 logger.info(`Unexpected default export without title in '${fileName}': ${JSON.stringify(fileExports.default)}`);
132 return;
133 }
134
135 this.csfExports[fileName] = Object.assign({}, fileExports, {
136 default: Object.assign({}, defaultExport, {
137 title
138 })
139 });
140 let sortedExports = namedExports; // prefer a user/loader provided `__namedExportsOrder` array if supplied
141 // we do this as es module exports are always ordered alphabetically
142 // see https://github.com/storybookjs/storybook/issues/9136
143
144 if (Array.isArray(__namedExportsOrder)) {
145 sortedExports = {};
146
147 __namedExportsOrder.forEach(name => {
148 const namedExport = namedExports[name];
149 if (namedExport) sortedExports[name] = namedExport;
150 });
151 }
152
153 Object.entries(sortedExports).filter(([key]) => isExportStory(key, defaultExport)).forEach(([key, storyExport]) => {
154 var _storyExport$paramete, _storyExport$story;
155
156 const exportName = storyNameFromExport(key);
157 const id = ((_storyExport$paramete = storyExport.parameters) === null || _storyExport$paramete === void 0 ? void 0 : _storyExport$paramete.__id) || toId(componentId || title, exportName);
158 const name = typeof storyExport !== 'function' && storyExport.name || storyExport.storyName || ((_storyExport$story = storyExport.story) === null || _storyExport$story === void 0 ? void 0 : _storyExport$story.name) || exportName;
159 this.stories[id] = {
160 id,
161 name,
162 title,
163 importPath: fileName
164 };
165 });
166 }
167
168}
\No newline at end of file