Skip to content

Commit

Permalink
Merge pull request #29343 from Sidnioulz/sidnioulz/component-entry-ta…
Browse files Browse the repository at this point in the history
…gs-intersection

Manager: Add tags property to ComponentEntry objects
  • Loading branch information
shilman authored Oct 12, 2024
2 parents 0eb384b + d60a9d7 commit 7a27337
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 0 deletions.
14 changes: 14 additions & 0 deletions code/core/src/manager-api/lib/intersect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default <T>(a: T[], b: T[]): T[] => {
// no point in intersecting if one of the input is ill-defined
if (!a || !b) {
return [];
}

return a.reduce((acc: T[], aValue) => {
if (b.includes(aValue)) {
acc.push(aValue);
}

return acc;
}, []);
};
4 changes: 4 additions & 0 deletions code/core/src/manager-api/lib/stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import memoize from 'memoizerific';
import { dedent } from 'ts-dedent';

import { type API, type State, combineParameters } from '../root';
import intersect from './intersect';
import merge from './merge';

const TITLE_PATH_SEPARATOR = /\s*\/\s*/;
Expand Down Expand Up @@ -273,6 +274,9 @@ export const transformStoryIndexToStoriesHash = (
children: [childId],
}),
});
// merge computes a union of arrays but we want an intersection on this
// specific array property, so it's easier to add it after the merge.
acc[id].tags = intersect(acc[id]?.tags ?? item.tags, item.tags);
} else {
acc[id] = merge<API_GroupEntry>((acc[id] || {}) as API_GroupEntry, {
type: 'group',
Expand Down
44 changes: 44 additions & 0 deletions code/core/src/manager-api/tests/intersect.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { describe, expect, it } from 'vitest';

import intersect from '../lib/intersect';

describe('Manager API utilities - intersect', () => {
it('returns identity when intersecting identity', () => {
const a = ['foo', 'bar'];
expect(intersect(a, a)).toEqual(a);
});

it('returns a when b is a superset of a', () => {
const a = ['foo', 'bar'];
const b = ['a', 'foo', 'b', 'bar', 'c', 'ter'];
expect(intersect(a, b)).toEqual(a);
});

it('returns b when a is a superset of b', () => {
const a = ['a', 'foo', 'b', 'bar', 'c', 'ter'];
const b = ['foo', 'bar'];
expect(intersect(a, b)).toEqual(b);
});

it('returns an intersection', () => {
const a = ['a', 'bar', 'b', 'c'];
const b = ['foo', 'bar', 'ter'];
expect(intersect(a, b)).toEqual(['bar']);
});

it('returns an empty set when there is no overlap', () => {
const a = ['a', 'b', 'c'];
const b = ['foo', 'bar', 'ter'];
expect(intersect(a, b)).toEqual([]);
});

it('returns an empty set if a is undefined', () => {
const b = ['foo', 'bar', 'ter'];
expect(intersect(undefined as unknown as [], b)).toEqual([]);
});

it('returns an empty set if b is undefined', () => {
const a = ['foo', 'bar', 'ter'];
expect(intersect(a, undefined as unknown as [])).toEqual([]);
});
});
54 changes: 54 additions & 0 deletions code/core/src/manager-api/tests/stories.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,57 @@ describe('stories API', () => {
name: '1',
});
});
it('intersects story/docs tags to compute tags for component entries', () => {
const moduleArgs = createMockModuleArgs({});
const { api } = initStories(moduleArgs as unknown as ModuleArgs);
const { store } = moduleArgs;
api.setIndex({
v: 5,
entries: {
'a--1': {
type: 'story',
id: 'a--1',
title: 'a',
name: '1',
tags: ['shared', 'one-specific'],
importPath: './a.ts',
},
'a--2': {
type: 'story',
id: 'a--2',
title: 'a',
name: '2',
tags: ['shared', 'two-specific'],
importPath: './a.ts',
},
},
});
const { index } = store.getState();
// We need exact key ordering, even if in theory JS doesn't guarantee it
expect(Object.keys(index!)).toEqual(['a', 'a--1', 'a--2']);
expect(index!.a).toMatchObject({
type: 'component',
id: 'a',
tags: ['shared'],
children: ['a--1', 'a--2'],
});
expect(index!['a--1']).toMatchObject({
type: 'story',
id: 'a--1',
parent: 'a',
title: 'a',
name: '1',
tags: ['shared', 'one-specific'],
});
expect(index!['a--2']).toMatchObject({
type: 'story',
id: 'a--2',
parent: 'a',
title: 'a',
name: '2',
tags: ['shared', 'two-specific'],
});
});
// Stories can get out of order for a few reasons -- see reproductions on
// https://github.com/storybookjs/storybook/issues/5518
it('does the right thing for out of order stories', async () => {
Expand Down Expand Up @@ -1453,6 +1504,7 @@ describe('stories API', () => {
"name": "a",
"parent": undefined,
"renderLabel": undefined,
"tags": [],
"type": "component",
},
"a--1": {
Expand Down Expand Up @@ -1518,6 +1570,7 @@ describe('stories API', () => {
"name": "a",
"parent": undefined,
"renderLabel": undefined,
"tags": [],
"type": "component",
},
"a--1": {
Expand Down Expand Up @@ -1559,6 +1612,7 @@ describe('stories API', () => {
"name": "a",
"parent": undefined,
"renderLabel": undefined,
"tags": [],
"type": "component",
},
"a--1": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const generateStories = ({ title, refId }: { title: string; refId?: string }): A
name: componentName,
children: [docsId],
parent: rootId,
tags: [],
},
// @ts-expect-error the missing fields are deprecated and replaced by the type prop
{
Expand Down
1 change: 1 addition & 0 deletions code/core/src/types/modules/api-stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface API_ComponentEntry extends API_BaseEntry {
type: 'component';
parent?: StoryId;
children: StoryId[];
tags: Tag[];
}

export interface API_DocsEntry extends API_BaseEntry {
Expand Down

0 comments on commit 7a27337

Please sign in to comment.