Skip to content

Commit

Permalink
git cherry-pick -m1 -x 4db60d6
Browse files Browse the repository at this point in the history
  • Loading branch information
shilman committed Jul 19, 2024
1 parent e3d2dec commit beb96d5
Show file tree
Hide file tree
Showing 14 changed files with 786 additions and 57 deletions.
227 changes: 206 additions & 21 deletions code/core/src/core-server/utils/StoryIndexGenerator.test.ts

Large diffs are not rendered by default.

52 changes: 37 additions & 15 deletions code/core/src/core-server/utils/StoryIndexGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-underscore-dangle */
import path from 'node:path';
import chalk from 'chalk';
import fs from 'fs-extra';
Expand All @@ -17,6 +18,7 @@ import type {
StoryIndex,
Indexer,
StorybookConfigRaw,
IndexInputStats,
} from '@storybook/core/types';
import { userOrAutoTitleFromSpecifier, sortStoriesV7 } from '@storybook/core/preview-api';
import { commonGlobOptions, normalizeStoryPath } from '@storybook/core/common';
Expand All @@ -27,14 +29,17 @@ import { analyze } from '@storybook/docs-mdx';
import { dedent } from 'ts-dedent';
import { autoName } from './autoName';
import { IndexingError, MultipleIndexingError } from './IndexingError';
import { addStats, type IndexStatsSummary } from './summarizeStats';

// Extended type to keep track of the csf meta id so we know the component id when referencing docs in `extractDocs`
type StoryIndexEntryWithMetaId = StoryIndexEntry & { metaId?: string };
type StoryIndexEntryWithExtra = StoryIndexEntry & {
extra: { metaId?: string; stats: IndexInputStats };
};
/** A .mdx file will produce a docs entry */
type DocsCacheEntry = DocsIndexEntry;
/** A *.stories.* file will produce a list of stories and possibly a docs entry */
type StoriesCacheEntry = {
entries: (StoryIndexEntryWithMetaId | DocsIndexEntry)[];
entries: (StoryIndexEntryWithExtra | DocsIndexEntry)[];
dependents: Path[];
type: 'stories';
};
Expand Down Expand Up @@ -104,6 +109,9 @@ export class StoryIndexGenerator {
// - the preview changes [not yet implemented]
private lastIndex?: StoryIndex | null;

// Cache the last value stats calculation, mirroring lastIndex
private lastStats?: IndexStatsSummary;

// Same as the above but for the error case
private lastError?: Error | null;

Expand Down Expand Up @@ -222,7 +230,7 @@ export class StoryIndexGenerator {
projectTags,
}: {
projectTags?: Tag[];
}): Promise<(IndexEntry | ErrorEntry)[]> {
}): Promise<{ entries: (IndexEntry | ErrorEntry)[]; stats: IndexStatsSummary }> {
// First process all the story files. Then, in a second pass,
// process the docs files. The reason for this is that the docs
// files may use the `<Meta of={XStories} />` syntax, which requires
Expand All @@ -237,7 +245,8 @@ export class StoryIndexGenerator {
this.extractDocs(specifier, absolutePath, projectTags)
);

return this.specifiers.flatMap((specifier) => {
const statsSummary = {} as IndexStatsSummary;
const entries = this.specifiers.flatMap((specifier) => {
const cache = this.specifierToCache.get(specifier);
invariant(
cache,
Expand All @@ -252,12 +261,17 @@ export class StoryIndexGenerator {

return entry.entries.map((item) => {
if (item.type === 'docs') return item;
// Drop the meta id as it isn't part of the index, we just used it for record keeping in `extractDocs`
const { metaId, ...existing } = item;

addStats(item.extra.stats, statsSummary);

// Drop extra data used for internal bookkeeping
const { extra, ...existing } = item;
return existing;
});
});
});

return { entries, stats: statsSummary };
}

findDependencies(absoluteImports: Path[]) {
Expand Down Expand Up @@ -341,22 +355,24 @@ export class StoryIndexGenerator {
]);
}

const entries: ((StoryIndexEntryWithMetaId | DocsCacheEntry) & { tags: Tag[] })[] =
const entries: ((StoryIndexEntryWithExtra | DocsCacheEntry) & { tags: Tag[] })[] =
indexInputs.map((input) => {
const name = input.name ?? storyNameFromExport(input.exportName);
const componentPath =
input.rawComponentPath &&
this.resolveComponentPath(input.rawComponentPath, absolutePath, matchPath);
const title = input.title ?? defaultMakeTitle();

// eslint-disable-next-line no-underscore-dangle
const id = input.__id ?? toId(input.metaId ?? title, storyNameFromExport(input.exportName));
const tags = combineTags(...projectTags, ...(input.tags ?? []));

return {
type: 'story',
id,
metaId: input.metaId,
extra: {
metaId: input.metaId,
stats: input.__stats ?? {},
},
name,
title,
importPath,
Expand Down Expand Up @@ -428,12 +444,12 @@ export class StoryIndexGenerator {

// Also, if `result.of` is set, it means that we're using the `<Meta of={XStories} />` syntax,
// so find the `title` defined the file that `meta` points to.
let csfEntry: StoryIndexEntryWithMetaId | undefined;
let csfEntry: StoryIndexEntryWithExtra | undefined;
if (result.of) {
const absoluteOf = makeAbsolute(result.of, normalizedPath, this.options.workingDir);
dependencies.forEach((dep) => {
if (dep.entries.length > 0) {
const first = dep.entries.find((e) => e.type !== 'docs') as StoryIndexEntryWithMetaId;
const first = dep.entries.find((e) => e.type !== 'docs') as StoryIndexEntryWithExtra;

if (
path
Expand Down Expand Up @@ -475,7 +491,7 @@ export class StoryIndexGenerator {
result.name ||
(csfEntry ? autoName(importPath, csfEntry.importPath, defaultName) : defaultName);

const id = toId(csfEntry?.metaId || title, name);
const id = toId(csfEntry?.extra.metaId || title, name);

const tags = combineTags(
...projectTags,
Expand Down Expand Up @@ -598,15 +614,20 @@ export class StoryIndexGenerator {
}

async getIndex() {
if (this.lastIndex) return this.lastIndex;
return (await this.getIndexAndStats()).storyIndex;
}

async getIndexAndStats(): Promise<{ storyIndex: StoryIndex; stats: IndexStatsSummary }> {
if (this.lastIndex && this.lastStats)
return { storyIndex: this.lastIndex, stats: this.lastStats };
if (this.lastError) throw this.lastError;

const previewCode = await this.getPreviewCode();
const projectTags = this.getProjectTags(previewCode);

// Extract any entries that are currently missing
// Pull out each file's stories into a list of stories, to be composed and sorted
const storiesList = await this.ensureExtracted({ projectTags });
const { entries: storiesList, stats } = await this.ensureExtracted({ projectTags });

try {
const errorEntries = storiesList.filter((entry) => entry.type === 'error');
Expand Down Expand Up @@ -635,12 +656,13 @@ export class StoryIndexGenerator {
previewCode && getStorySortParameter(previewCode)
);

this.lastStats = stats;
this.lastIndex = {
v: 5,
entries: sorted,
};

return this.lastIndex;
return { storyIndex: this.lastIndex, stats: this.lastStats };
} catch (err) {
this.lastError = err == null || err instanceof Error ? err : undefined;
invariant(this.lastError);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const component = {};
export default {
component,
};

export const WithPlay = {
play: async () => {},
};

export const WithStoryFn = () => {};

export const WithRender = {
render: () => {},
};

export const WithTest = {
beforeEach: async () => {},
play: async ({ mount }) => {
await mount();
},
};

export const WithCSF1 = {
parameters: {},
decorators: [],
loaders: [],
};
60 changes: 48 additions & 12 deletions code/core/src/core-server/utils/__tests__/index-extraction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,12 @@ describe('story extraction', () => {
"entries": [
{
"componentPath": undefined,
"extra": {
"metaId": "a",
"stats": {},
},
"id": "a--story-one",
"importPath": "./src/A.stories.js",
"metaId": "a",
"name": "Story One",
"tags": [
"story-tag-from-indexer",
Expand All @@ -74,9 +77,12 @@ describe('story extraction', () => {
},
{
"componentPath": undefined,
"extra": {
"metaId": "custom-id",
"stats": {},
},
"id": "some-fully-custom-id",
"importPath": "./src/A.stories.js",
"metaId": "custom-id",
"name": "Another Story Name",
"tags": [
"story-tag-from-indexer",
Expand Down Expand Up @@ -118,9 +124,12 @@ describe('story extraction', () => {
"entries": [
{
"componentPath": undefined,
"extra": {
"metaId": undefined,
"stats": {},
},
"id": "f--story-one",
"importPath": "./src/first-nested/deeply/F.stories.js",
"metaId": undefined,
"name": "Story One",
"tags": [],
"title": "F",
Expand Down Expand Up @@ -164,9 +173,12 @@ describe('story extraction', () => {
"entries": [
{
"componentPath": undefined,
"extra": {
"metaId": "a",
"stats": {},
},
"id": "a--story-one",
"importPath": "./src/first-nested/deeply/F.stories.js",
"metaId": "a",
"name": "Story One",
"tags": [
"story-tag-from-indexer",
Expand Down Expand Up @@ -212,9 +224,12 @@ describe('story extraction', () => {
"entries": [
{
"componentPath": undefined,
"extra": {
"metaId": "a",
"stats": {},
},
"id": "a--story-one",
"importPath": "./src/A.stories.js",
"metaId": "a",
"name": "Story One",
"tags": [
"story-tag-from-indexer",
Expand Down Expand Up @@ -278,9 +293,12 @@ describe('story extraction', () => {
"entries": [
{
"componentPath": undefined,
"extra": {
"metaId": undefined,
"stats": {},
},
"id": "a--story-one",
"importPath": "./src/A.stories.js",
"metaId": undefined,
"name": "Story One",
"tags": [
"story-tag-from-indexer",
Expand All @@ -290,9 +308,12 @@ describe('story extraction', () => {
},
{
"componentPath": undefined,
"extra": {
"metaId": undefined,
"stats": {},
},
"id": "custom-title--story-two",
"importPath": "./src/A.stories.js",
"metaId": undefined,
"name": "Custom Name For Second Story",
"tags": [
"story-tag-from-indexer",
Expand All @@ -302,9 +323,12 @@ describe('story extraction', () => {
},
{
"componentPath": undefined,
"extra": {
"metaId": "custom-meta-id",
"stats": {},
},
"id": "custom-meta-id--story-three",
"importPath": "./src/A.stories.js",
"metaId": "custom-meta-id",
"name": "Story Three",
"tags": [
"story-tag-from-indexer",
Expand Down Expand Up @@ -347,9 +371,12 @@ describe('story extraction', () => {
"entries": [
{
"componentPath": undefined,
"extra": {
"metaId": undefined,
"stats": {},
},
"id": "a--story-one",
"importPath": "./src/A.stories.js",
"metaId": undefined,
"name": "Story One",
"tags": [
"story-tag-from-indexer",
Expand Down Expand Up @@ -397,9 +424,12 @@ describe('docs entries from story extraction', () => {
"entries": [
{
"componentPath": undefined,
"extra": {
"metaId": undefined,
"stats": {},
},
"id": "a--story-one",
"importPath": "./src/A.stories.js",
"metaId": undefined,
"name": "Story One",
"tags": [
"story-tag-from-indexer",
Expand Down Expand Up @@ -457,9 +487,12 @@ describe('docs entries from story extraction', () => {
},
{
"componentPath": undefined,
"extra": {
"metaId": undefined,
"stats": {},
},
"id": "a--story-one",
"importPath": "./src/A.stories.js",
"metaId": undefined,
"name": "Story One",
"tags": [
"autodocs",
Expand Down Expand Up @@ -506,9 +539,12 @@ describe('docs entries from story extraction', () => {
"entries": [
{
"componentPath": undefined,
"extra": {
"metaId": undefined,
"stats": {},
},
"id": "a--story-one",
"importPath": "./src/A.stories.js",
"metaId": undefined,
"name": "Story One",
"tags": [
"autodocs",
Expand Down
9 changes: 5 additions & 4 deletions code/core/src/core-server/utils/doTelemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export async function doTelemetry(
) {
if (!core?.disableTelemetry) {
initializedStoryIndexGenerator.then(async (generator) => {
let storyIndex: StoryIndex | undefined;
let indexAndStats;
try {
storyIndex = await generator?.getIndex();
indexAndStats = await generator?.getIndexAndStats();
} catch (err) {
// If we fail to get the index, treat it as a recoverable error, but send it up to telemetry
// as if we crashed. In the future we will revisit this to send a distinct error
Expand All @@ -36,10 +36,11 @@ export async function doTelemetry(
const payload = {
precedingUpgrade: await getPrecedingUpgrade(),
};
if (storyIndex) {
if (indexAndStats) {
Object.assign(payload, {
versionStatus: versionUpdates && versionCheck ? versionStatus(versionCheck) : 'disabled',
storyIndex: summarizeIndex(storyIndex),
storyIndex: summarizeIndex(indexAndStats.storyIndex),
storyStats: indexAndStats.stats,
});
}
telemetry('dev', payload, { configDir: options.configDir });
Expand Down
Loading

0 comments on commit beb96d5

Please sign in to comment.