UNPKG

6.68 kBJavaScriptView Raw
1import "core-js/modules/es.array.reduce.js";
2import memoize from 'memoizerific';
3import deprecate from 'util-deprecate';
4import dedent from 'ts-dedent';
5import mapValues from 'lodash/mapValues';
6import countBy from 'lodash/countBy';
7import global from 'global';
8import { sanitize } from '@storybook/csf';
9import { combineParameters } from '../index';
10import merge from './merge';
11const {
12 FEATURES
13} = global;
14const warnLegacyShowRoots = deprecate(() => {}, dedent`
15 The 'showRoots' config option is deprecated and will be removed in Storybook 7.0. Use 'sidebar.showRoots' instead.
16 Read more about it in the migration guide: https://github.com/storybookjs/storybook/blob/master/MIGRATION.md
17 `);
18const warnChangedDefaultHierarchySeparators = deprecate(() => {}, dedent`
19 The default hierarchy separators changed in Storybook 6.0.
20 '|' and '.' will no longer create a hierarchy, but codemods are available.
21 Read more about it in the migration guide: https://github.com/storybookjs/storybook/blob/master/MIGRATION.md
22 `);
23export const denormalizeStoryParameters = ({
24 globalParameters,
25 kindParameters,
26 stories
27}) => {
28 return mapValues(stories, storyData => Object.assign({}, storyData, {
29 parameters: combineParameters(globalParameters, kindParameters[storyData.kind], storyData.parameters)
30 }));
31};
32const STORY_KIND_PATH_SEPARATOR = /\s*\/\s*/;
33export const transformStoryIndexToStoriesHash = (index, {
34 provider
35}) => {
36 const countByTitle = countBy(Object.values(index.stories), 'title');
37 const input = Object.entries(index.stories).reduce((acc, [id, {
38 title,
39 name,
40 importPath,
41 parameters
42 }]) => {
43 const docsOnly = name === 'Page' && countByTitle[title] === 1;
44 acc[id] = {
45 id,
46 kind: title,
47 name,
48 parameters: Object.assign({
49 fileName: importPath,
50 options: {},
51 docsOnly
52 }, parameters)
53 };
54 return acc;
55 }, {});
56 return transformStoriesRawToStoriesHash(input, {
57 provider,
58 prepared: false
59 });
60};
61export const transformStoriesRawToStoriesHash = (input, {
62 provider,
63 prepared = true
64}) => {
65 const values = Object.values(input).filter(Boolean);
66 const usesOldHierarchySeparator = values.some(({
67 kind
68 }) => kind.match(/\.|\|/)); // dot or pipe
69
70 const storiesHashOutOfOrder = values.reduce((acc, item) => {
71 var _item$parameters;
72
73 const {
74 kind,
75 parameters
76 } = item;
77 const {
78 sidebar = {},
79 showRoots: deprecatedShowRoots
80 } = provider.getConfig();
81 const {
82 showRoots = deprecatedShowRoots,
83 collapsedRoots = [],
84 renderLabel
85 } = sidebar;
86
87 if (typeof deprecatedShowRoots !== 'undefined') {
88 warnLegacyShowRoots();
89 }
90
91 const setShowRoots = typeof showRoots !== 'undefined';
92
93 if (usesOldHierarchySeparator && !setShowRoots && FEATURES !== null && FEATURES !== void 0 && FEATURES.warnOnLegacyHierarchySeparator) {
94 warnChangedDefaultHierarchySeparators();
95 }
96
97 const groups = kind.trim().split(STORY_KIND_PATH_SEPARATOR);
98 const root = (!setShowRoots || showRoots) && groups.length > 1 ? [groups.shift()] : [];
99 const rootAndGroups = [...root, ...groups].reduce((list, name, index) => {
100 const parent = index > 0 && list[index - 1].id;
101 const id = sanitize(parent ? `${parent}-${name}` : name);
102
103 if (parent === id) {
104 throw new Error(dedent`
105 Invalid part '${name}', leading to id === parentId ('${id}'), inside kind '${kind}'
106
107 Did you create a path that uses the separator char accidentally, such as 'Vue <docs/>' where '/' is a separator char? See https://github.com/storybookjs/storybook/issues/6128
108 `);
109 }
110
111 if (root.length && index === 0) {
112 list.push({
113 type: 'root',
114 id,
115 name,
116 depth: index,
117 children: [],
118 isComponent: false,
119 isLeaf: false,
120 isRoot: true,
121 renderLabel,
122 startCollapsed: collapsedRoots.includes(id)
123 });
124 } else {
125 list.push({
126 type: 'group',
127 id,
128 name,
129 parent,
130 depth: index,
131 children: [],
132 isComponent: false,
133 isLeaf: false,
134 isRoot: false,
135 renderLabel,
136 parameters: {
137 docsOnly: parameters === null || parameters === void 0 ? void 0 : parameters.docsOnly,
138 viewMode: parameters === null || parameters === void 0 ? void 0 : parameters.viewMode
139 }
140 });
141 }
142
143 return list;
144 }, []);
145 const paths = [...rootAndGroups.map(({
146 id
147 }) => id), item.id]; // Ok, now let's add everything to the store
148
149 rootAndGroups.forEach((group, index) => {
150 const child = paths[index + 1];
151 const {
152 id
153 } = group;
154 acc[id] = merge(acc[id] || {}, Object.assign({}, group, child && {
155 children: [child]
156 }));
157 });
158 acc[item.id] = Object.assign({
159 type: (_item$parameters = item.parameters) !== null && _item$parameters !== void 0 && _item$parameters.docsOnly ? 'docs' : 'story'
160 }, item, {
161 depth: rootAndGroups.length,
162 parent: rootAndGroups[rootAndGroups.length - 1].id,
163 isLeaf: true,
164 isComponent: false,
165 isRoot: false,
166 renderLabel,
167 prepared
168 });
169 return acc;
170 }, {});
171
172 function addItem(acc, item) {
173 if (!acc[item.id]) {
174 // If we were already inserted as part of a group, that's great.
175 acc[item.id] = item;
176 const {
177 children
178 } = item;
179
180 if (children) {
181 const childNodes = children.map(id => storiesHashOutOfOrder[id]);
182
183 if (childNodes.every(childNode => childNode.isLeaf)) {
184 acc[item.id].isComponent = true;
185 acc[item.id].type = 'component';
186 }
187
188 childNodes.forEach(childNode => addItem(acc, childNode));
189 }
190 }
191
192 return acc;
193 }
194
195 return Object.values(storiesHashOutOfOrder).reduce(addItem, {});
196};
197export function isRoot(item) {
198 if (item) {
199 return item.isRoot;
200 }
201
202 return false;
203}
204export function isGroup(item) {
205 if (item) {
206 return !item.isRoot && !item.isLeaf;
207 }
208
209 return false;
210}
211export function isStory(item) {
212 if (item) {
213 return item.isLeaf;
214 }
215
216 return false;
217}
218export const getComponentLookupList = memoize(1)(hash => {
219 return Object.entries(hash).reduce((acc, i) => {
220 const value = i[1];
221
222 if (value.isComponent) {
223 acc.push([...i[1].children]);
224 }
225
226 return acc;
227 }, []);
228});
229export const getStoriesLookupList = memoize(1)(hash => {
230 return Object.keys(hash).filter(k => !(hash[k].children || Array.isArray(hash[k])));
231});
\No newline at end of file