Skip to content

Commit

Permalink
Merge pull request #18763 from storybookjs/tom/sb-475-support-storyst…
Browse files Browse the repository at this point in the history
…orev6

Support DocsPage in v6 store
  • Loading branch information
tmeasday committed Jul 26, 2022
2 parents ff16fc8 + 23a2c7c commit 3db4db6
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 28 deletions.
2 changes: 1 addition & 1 deletion code/cypress/helper.ts
Expand Up @@ -20,7 +20,7 @@ export const visit = (route = '') => {
expect(element).not.null;

if (element !== null) {
expect(element.querySelector('#root > *')).not.null;
expect(element.querySelector('#root > *, #docs-root > *')).not.null;
}
});
});
Expand Down
41 changes: 31 additions & 10 deletions code/lib/api/src/lib/stories.ts
Expand Up @@ -5,6 +5,7 @@ import { dedent } from 'ts-dedent';
import mapValues from 'lodash/mapValues';
import countBy from 'lodash/countBy';
import global from 'global';
import { toId, sanitize } from '@storybook/csf';
import type {
StoryId,
ComponentTitle,
Expand All @@ -13,8 +14,9 @@ import type {
Args,
ArgTypes,
Parameters,
ComponentId,
} from '@storybook/csf';
import { sanitize } from '@storybook/csf';
import type { DocsOptions } from '@storybook/core-common';

import { combineParameters } from '../index';
import merge from './merge';
Expand Down Expand Up @@ -145,6 +147,7 @@ export interface SetStoriesStory {
id: StoryId;
name: string;
refId?: string;
componentId?: ComponentId;
kind: StoryKind;
parameters: {
fileName: string;
Expand Down Expand Up @@ -268,16 +271,21 @@ export interface PreparedStoryIndex {

export const transformSetStoriesStoryDataToStoriesHash = (
data: SetStoriesStoryData,
{ provider, docsMode }: { provider: Provider; docsMode: boolean }
{ provider, docsOptions }: { provider: Provider; docsOptions: DocsOptions }
) =>
transformStoryIndexToStoriesHash(transformSetStoriesStoryDataToPreparedStoryIndex(data), {
provider,
docsMode,
});
transformStoryIndexToStoriesHash(
transformSetStoriesStoryDataToPreparedStoryIndex(data, { docsOptions }),
{
provider,
docsOptions,
}
);

const transformSetStoriesStoryDataToPreparedStoryIndex = (
stories: SetStoriesStoryData
stories: SetStoriesStoryData,
{ docsOptions }: { docsOptions: DocsOptions }
): PreparedStoryIndex => {
const seenTitles = new Set<ComponentTitle>();
const entries: PreparedStoryIndex['entries'] = Object.entries(stories).reduce(
(acc, [id, story]) => {
if (!story) return acc;
Expand All @@ -296,6 +304,19 @@ const transformSetStoriesStoryDataToPreparedStoryIndex = (
...base,
};
} else {
if (!seenTitles.has(base.title) && docsOptions.docsPage) {
const name = docsOptions.defaultName;
const docsId = toId(story.componentId || base.title, name);
seenTitles.add(base.title);
acc[docsId] = {
type: 'docs',
storiesImports: [],
...base,
id: docsId,
name,
};
}

const { argTypes, args, initialArgs } = story;
acc[id] = {
type: 'story',
Expand Down Expand Up @@ -340,10 +361,10 @@ export const transformStoryIndexToStoriesHash = (
index: PreparedStoryIndex,
{
provider,
docsMode,
docsOptions,
}: {
provider: Provider;
docsMode: boolean;
docsOptions: DocsOptions;
}
): StoriesHash => {
if (!index.v) throw new Error('Composition: Missing stories.json version');
Expand All @@ -364,7 +385,7 @@ export const transformStoryIndexToStoriesHash = (
}

const storiesHashOutOfOrder = Object.values(entryValues).reduce((acc, item) => {
if (docsMode && item.type !== 'docs') return acc;
if (docsOptions.docsMode && item.type !== 'docs') return acc;

// First, split the title into a set of names, separated by '/' and trimmed.
const { title } = item;
Expand Down
6 changes: 3 additions & 3 deletions code/lib/api/src/modules/refs.ts
Expand Up @@ -133,7 +133,7 @@ const map = (
};

export const init: ModuleFn<SubAPI, SubState, void> = (
{ store, provider, singleStory, docsOptions: { docsMode } = {} },
{ store, provider, singleStory, docsOptions = {} },
{ runCheck = true } = {}
) => {
const api: SubAPI = {
Expand Down Expand Up @@ -249,10 +249,10 @@ export const init: ModuleFn<SubAPI, SubState, void> = (
if (setStoriesData) {
storiesHash = transformSetStoriesStoryDataToStoriesHash(
map(setStoriesData, ref, { storyMapper }),
{ provider, docsMode }
{ provider, docsOptions }
);
} else if (storyIndex) {
storiesHash = transformStoryIndexToStoriesHash(storyIndex, { provider, docsMode });
storiesHash = transformStoryIndexToStoriesHash(storyIndex, { provider, docsOptions });
}
if (storiesHash) storiesHash = addRefIds(storiesHash, ref);

Expand Down
6 changes: 3 additions & 3 deletions code/lib/api/src/modules/stories.ts
Expand Up @@ -122,7 +122,7 @@ export const init: ModuleFn<SubAPI, SubState, true> = ({
provider,
storyId: initialStoryId,
viewMode: initialViewMode,
docsOptions: { docsMode } = {},
docsOptions = {},
}) => {
const api: SubAPI = {
storyId: toId,
Expand Down Expand Up @@ -211,7 +211,7 @@ export const init: ModuleFn<SubAPI, SubState, true> = ({
// Now create storiesHash by reordering the above by group
const hash = transformSetStoriesStoryDataToStoriesHash(input, {
provider,
docsMode,
docsOptions,
});

await store.setState({
Expand Down Expand Up @@ -359,7 +359,7 @@ export const init: ModuleFn<SubAPI, SubState, true> = ({
setStoryList: async (storyIndex: StoryIndex) => {
const hash = transformStoryIndexToStoriesHash(storyIndex, {
provider,
docsMode,
docsOptions,
});

await store.setState({
Expand Down
73 changes: 73 additions & 0 deletions code/lib/api/src/tests/stories.test.ts
Expand Up @@ -430,6 +430,79 @@ describe('stories API', () => {
children: ['b--1'],
});
});

it('adds docs entries when docsPage is enabled', () => {
const navigate = jest.fn();
const store = createMockStore({});

const {
api: { setStories },
} = initStories({
store,
navigate,
provider,
docsOptions: { docsPage: true, defaultName: 'Docs' },
} as any as any);

provider.getConfig.mockReturnValue({ sidebar: { showRoots: false } });
setStories(setStoriesData);

const { storiesHash: storedStoriesHash } = store.getState();

// We need exact key ordering, even if in theory JS doesn't guarantee it
expect(Object.keys(storedStoriesHash)).toEqual([
'a',
'a--docs',
'a--1',
'a--2',
'b',
'b-c',
'b-c--docs',
'b-c--1',
'b-d',
'b-d--docs',
'b-d--1',
'b-d--2',
'b-e',
'b-e--docs',
'custom-id--1',
]);
expect(storedStoriesHash['a--docs']).toMatchObject({
type: 'docs',
id: 'a--docs',
parent: 'a',
title: 'a',
name: 'Docs',
storiesImports: [],
});

expect(storedStoriesHash['b-c--docs']).toMatchObject({
type: 'docs',
id: 'b-c--docs',
parent: 'b-c',
title: 'b/c',
name: 'Docs',
storiesImports: [],
});

expect(storedStoriesHash['b-d--docs']).toMatchObject({
type: 'docs',
id: 'b-d--docs',
parent: 'b-d',
title: 'b/d',
name: 'Docs',
storiesImports: [],
});

expect(storedStoriesHash['b-e--docs']).toMatchObject({
type: 'docs',
id: 'b-e--docs',
parent: 'b-e',
title: 'b/e',
name: 'Docs',
storiesImports: [],
});
});
});

// Can't currently run these tests as cannot set this on the events
Expand Down
Expand Up @@ -9,7 +9,7 @@ import TerserWebpackPlugin from 'terser-webpack-plugin';
import VirtualModulePlugin from 'webpack-virtual-modules';
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';

import type { Options, CoreConfig } from '@storybook/core-common';
import type { Options, CoreConfig, DocsOptions } from '@storybook/core-common';
import {
stringifyProcessEnvs,
handlebars,
Expand Down Expand Up @@ -87,6 +87,7 @@ export default async (
const coreOptions = await presets.apply<CoreConfig>('core');
const builderOptions: BuilderOptions =
typeof coreOptions.builder === 'string' ? {} : coreOptions.builder?.options || {};
const docsOptions = await presets.apply<DocsOptions>('docs');

const configs = [
...(await presets.apply('config', [], options)),
Expand Down Expand Up @@ -214,6 +215,7 @@ export default async (
...specifier,
importPathMatcher: specifier.importPathMatcher.source,
})),
DOCS_OPTIONS: docsOptions,
SERVER_CHANNEL_URL: serverChannelUrl,
},
headHtmlSnippet,
Expand Down
54 changes: 44 additions & 10 deletions code/lib/client-api/src/StoryStoreFacade.ts
Expand Up @@ -2,7 +2,13 @@
import global from 'global';
import { dedent } from 'ts-dedent';
import { SynchronousPromise } from 'synchronous-promise';
import { toId, isExportStory, storyNameFromExport } from '@storybook/csf';
import {
toId,
isExportStory,
storyNameFromExport,
ComponentTitle,
ComponentId,
} from '@storybook/csf';
import type { StoryId, AnyFramework, Parameters, StoryFn } from '@storybook/csf';
import { StoryStore, userOrAutoTitle, sortStoriesV6 } from '@storybook/store';
import type {
Expand All @@ -16,6 +22,7 @@ import type {
} from '@storybook/store';
import { logger } from '@storybook/client-logger';
import deprecate from 'util-deprecate';
import type { DocsOptions } from '@storybook/core-common';

export interface GetStorybookStory<TFramework extends AnyFramework> {
name: string;
Expand All @@ -34,7 +41,7 @@ const docs2Warning = deprecate(() => {},
export class StoryStoreFacade<TFramework extends AnyFramework> {
projectAnnotations: NormalizedProjectAnnotations<TFramework>;

entries: StoryIndex['entries'];
entries: Record<StoryId, IndexEntry & { componentId?: ComponentId }>;

csfExports: Record<Path, ModuleExports>;

Expand Down Expand Up @@ -71,19 +78,27 @@ export class StoryStoreFacade<TFramework extends AnyFramework> {
const storyEntries = Object.entries(this.entries);
// Add the kind parameters and global parameters to each entry
const sortableV6: [StoryId, Story<TFramework>, Parameters, Parameters][] = storyEntries.map(
([storyId, { importPath }]) => {
([storyId, { type, importPath, ...entry }]) => {
const exports = this.csfExports[importPath];
const csfFile = store.processCSFFileWithCache<TFramework>(
exports,
importPath,
exports.default.title
);
return [
storyId,
store.storyFromCSFFile({ storyId, csfFile }),
csfFile.meta.parameters,
this.projectAnnotations.parameters,
];

let storyLike: Story<TFramework>;
if (type === 'story') {
storyLike = store.storyFromCSFFile({ storyId, csfFile });
} else {
storyLike = {
...entry,
story: entry.name,
kind: entry.title,
componentId: toId(entry.componentId || entry.title),
parameters: { fileName: importPath },
} as any;
}
return [storyId, storyLike, csfFile.meta.parameters, this.projectAnnotations.parameters];
}
);

Expand Down Expand Up @@ -188,6 +203,8 @@ export class StoryStoreFacade<TFramework extends AnyFramework> {
});
}

const docsOptions = (global.DOCS_OPTIONS || {}) as DocsOptions;
const seenTitles = new Set<ComponentTitle>();
Object.entries(sortedExports)
.filter(([key]) => isExportStory(key, defaultExport))
.forEach(([key, storyExport]: [string, any]) => {
Expand All @@ -199,12 +216,29 @@ export class StoryStoreFacade<TFramework extends AnyFramework> {
storyExport.story?.name ||
exportName;

if (!seenTitles.has(title) && docsOptions.docsPage) {
const name = docsOptions.defaultName;
const docsId = toId(componentId || title, name);
seenTitles.add(title);
this.entries[docsId] = {
type: 'docs',
standalone: false,
id: docsId,
title,
name,
importPath: fileName,
storiesImports: [],
componentId,
};
}

this.entries[id] = {
type: 'story',
id,
name,
title,
importPath: fileName,
type: 'story',
componentId,
};
});
}
Expand Down

0 comments on commit 3db4db6

Please sign in to comment.