diff --git a/src/index.test.ts b/src/index.test.ts index a21a41f..dd2858a 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,4 +1,4 @@ -import { toId, storyNameFromExport, isExportStory } from './index.js'; +import { toId, storyNameFromExport, isExportStory, combineTags } from './index.js'; describe('toId', () => { const testCases: [string, string, string | undefined, string][] = [ @@ -93,3 +93,21 @@ describe('isExportStory', () => { expect(isExportStory('a', { includeStories: /a/, excludeStories: /b/ })).toBeTruthy(); }); }); + +describe('combineTags', () => { + it.each([ + [[], []], + [ + ['a', 'b'], + ['a', 'b'], + ], + [ + ['a', 'b', 'b'], + ['a', 'b'], + ], + [['a', 'b', '!b'], ['a']], + [['b', '!b', 'b'], ['b']], + ])('combineTags(%o) -> %o', (tags, expected) => { + expect(combineTags(...tags)).toEqual(expected); + }); +}); diff --git a/src/index.ts b/src/index.ts index 5fd9d55..a7bd966 100644 --- a/src/index.ts +++ b/src/index.ts @@ -83,5 +83,20 @@ export const parseKind = (kind: string, { rootSeparator, groupSeparator }: Separ }; }; +/** + * Combine a set of project / meta / story tags, removing duplicates and handling negations. + */ +export const combineTags = (...tags: string[]): string[] => { + const result = tags.reduce((acc, tag) => { + if (tag.startsWith('!')) { + acc.delete(tag.slice(1)); + } else { + acc.add(tag); + } + return acc; + }, new Set()); + return Array.from(result); +}; + export { includeConditionalArg } from './includeConditionalArg'; export * from './story'; diff --git a/src/story.ts b/src/story.ts index 9af15e1..7d4c97a 100644 --- a/src/story.ts +++ b/src/story.ts @@ -377,6 +377,11 @@ export type BaseAnnotations * Define a custom render function for the story(ies). If not passed, a default render function by the renderer will be used. */ render?: ArgsStoryFn; + + /** + * Named tags for a story, used to filter stories in different contexts. + */ + tags?: Tag[]; }; export type ProjectAnnotations< @@ -485,11 +490,6 @@ export interface ComponentAnnotations; - - /** - * Named tags for a story, used to filter stories in different contexts. - */ - tags?: Tag[]; } export type StoryAnnotations< @@ -512,11 +512,6 @@ export type StoryAnnotations< */ play?: PlayFunction; - /** - * Named tags for a story, used to filter stories in different contexts. - */ - tags?: Tag[]; - /** @deprecated */ story?: Omit, 'story'>; // eslint-disable-next-line @typescript-eslint/ban-types