Use new storyId format for story_store

This commit is contained in:
Tom Coleman 2018-12-21 16:39:12 +11:00
parent dbbd06173f
commit 0d7d8d2404
3 changed files with 118 additions and 39 deletions

View File

@ -7,7 +7,7 @@
// 2. replace all runs of '-' with a single '-',
// except if they are at the end, in which case, replace them with ''
function sanitize(string) {
export function sanitize(string) {
return string
.toLowerCase()
.replace(/[^a-z0-9-]/g, '-')

View File

@ -6,6 +6,7 @@ import mergeWith from 'lodash.mergewith';
import isEqual from 'lodash.isequal';
import Events from '@storybook/core-events';
import debounce from 'lodash.debounce';
import toId, { sanitize } from './id';
// TODO: these are copies from components/nav/lib
// refactor to DRY
@ -52,8 +53,6 @@ export const splitPath = (path, { rootSeparator, groupSeparator }) => {
};
};
export { toKey };
let count = 0;
function getId() {
@ -145,58 +144,68 @@ export default class StoryStore extends EventEmitter {
getSelection = () => this._selection;
addStory(
{ kind, name, story, getDecorated, parameters = {} },
{ kind, name: storyName, story, getDecorated, parameters = {} },
{ rootSeparator, groupSeparator }
) {
const { _data } = this;
const { root, groups } = splitPath(kind, { rootSeparator, groupSeparator });
const rootId = root ? toKey(root) : null;
const h = []
const rootAndGroups = []
.concat(root || [])
.concat(groups)
.map(toGroup);
.map(toGroup)
// Map a bunch of extra fields onto the groups, collecting the path as we go (thus the reduce)
.reduce((soFar, group, index, original) => {
const { name } = group;
const path = sanitize(index === 0 ? name : `${soFar[index - 1].path}-${name}`);
return soFar.concat([
{
...group,
path,
depth: index,
isComponent: index === original.length - 1,
isRoot: index === 0,
},
]);
}, []);
const id = h
.map(g => g.id)
.concat(toKey(name))
.join('-');
const storyId = toId(kind, storyName);
const paths = [...rootAndGroups.map(g => g.path), storyId];
const child = toChild({
// Ok, now let's add everything to the store
rootAndGroups.forEach((group, index) => {
const child = paths[index + 1];
const { path } = group;
_data[path] = merge(_data[path] || {}, {
...group,
...(child && { children: [child] }),
});
});
// Check that we don't already have this item in the story
if (_data[storyId]) {
// TODO -- we need a better error and some docs here
throw new Error(`Story with id ${storyId} already exists in the store!
Perhaps you added the same story twice, or you have a name collision?
Story ids need to be unique -- ensure you aren't using the same names modolo url-sanitization.`);
}
_data[storyId] = toChild({
kind,
name,
name: storyName,
story,
getDecorated,
parameters,
id,
id: storyId,
path: storyId,
depth: rootAndGroups.length,
isComponent: false,
isRoot: false,
});
// add groups
h.reduceRight((childId, group, index, list) => {
const path = list
.slice(0, index + 1)
.map(g => g.id)
.join('-');
const existing = _data[path] || {};
const isRoot = group.id === rootId;
const isComponent = index === list.length - 1;
const depth = index;
_data[path] = merge(
existing,
merge(group, { children: [childId], isRoot, isComponent, depth, path })
);
return path;
}, id);
// add item
const existing = _data[id] || {};
_data[id] = merge(existing, { ...child, depth: h.length, path: id });
// LEGACY DATA
this.addLegacyStory({ kind, name, story, getDecorated, parameters });
this.addLegacyStory({ kind, name: storyName, story, getDecorated, parameters });
// LET'S SEND IT TO THE MANAGER
this.pushToManager();

View File

@ -9,6 +9,76 @@ const make = (kind, name, story, parameters = {}) => [
];
describe('preview.story_store', () => {
describe('raw storage', () => {
it('stores basic kinds and stories w/ correct keys', () => {
const store = new StoryStore({ channel });
store.addStory(...make('a', '1', () => 0));
store.addStory(...make('a', '2', () => 0));
store.addStory(...make('b', '1', () => 0));
const extracted = store.extract();
// We need exact key ordering, even if in theory JS doens't guarantee it
expect(Object.keys(extracted)).toEqual(['a', 'a--1', 'a--2', 'b', 'b--1']);
expect(extracted.a).toMatchObject({
path: 'a',
children: ['a--1', 'a--2'],
isRoot: true,
isComponent: true,
depth: 0,
});
expect(extracted['a--1']).toMatchObject({
id: 'a--1',
path: 'a--1',
kind: 'a',
name: '1',
parameters: {},
depth: 1,
isRoot: false,
isComponent: false,
});
});
it('stores root and groups also', () => {
const store = new StoryStore({ channel });
store.addStory(...make('a|b/c/d', '1', () => 0));
const extracted = store.extract();
// We need exact key ordering, even if in theory JS doens't guarantee it
expect(Object.keys(extracted)).toEqual(['a', 'a-b', 'a-b-c', 'a-b-c-d', 'a-b-c-d--1']);
expect(extracted.a).toMatchObject({
name: 'a',
isRoot: true,
isComponent: false,
children: ['a-b'],
});
expect(extracted['a-b']).toMatchObject({
name: 'b',
isRoot: false,
isComponent: false,
children: ['a-b-c'],
});
expect(extracted['a-b-c']).toMatchObject({
name: 'c',
isRoot: false,
isComponent: false,
children: ['a-b-c-d'],
});
expect(extracted['a-b-c-d']).toMatchObject({
name: 'd',
isRoot: false,
isComponent: true,
children: ['a-b-c-d--1'],
});
expect(extracted['a-b-c-d--1']).toMatchObject({
kind: 'a|b/c/d',
name: '1',
isRoot: false,
isComponent: false,
});
});
});
describe('dumpStoryBook', () => {
it('should return nothing when empty', () => {
const store = new StoryStore({ channel });