From ef2c3b82cab27d188beda60057abda8bfea65d5e Mon Sep 17 00:00:00 2001 From: Aron Griffis Date: Thu, 30 Mar 2023 14:35:06 -0400 Subject: [PATCH] fix: handle button.group.stories.js in auto-title The stripExtension() function aggressively removed everything after the first dot in the filename. It should remove only (for example) .js or .stories.js or .story.js See the new test in autoTitle.test.ts for example. Additionally the stripExtension() function was pulling double-duty by cleaning up an empty leading string, a leftover from calling pathJoin([titlePrefix, suffix]) with empty titlePrefix. Handle this properly in the earlier code instead of hacking stripExtension(). --- .../src/modules/store/autoTitle.test.ts | 10 ++++ .../src/modules/store/autoTitle.ts | 46 +++++++------------ 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/code/lib/preview-api/src/modules/store/autoTitle.test.ts b/code/lib/preview-api/src/modules/store/autoTitle.test.ts index e4c1fe23dbb2..c117b44a05a9 100644 --- a/code/lib/preview-api/src/modules/store/autoTitle.test.ts +++ b/code/lib/preview-api/src/modules/store/autoTitle.test.ts @@ -187,6 +187,16 @@ describe('userOrAutoTitleFromSpecifier', () => { ).toMatchInlineSnapshot(`to/button`); }); + it('match with dotted component', () => { + expect( + userOrAuto( + './path/to/button/button.group.stories.js', + normalizeStoriesEntry({ directory: './path' }, options), + undefined + ) + ).toMatchInlineSnapshot(`to/button/button.group`); + }); + it('match with hyphen path', () => { expect( userOrAuto( diff --git a/code/lib/preview-api/src/modules/store/autoTitle.ts b/code/lib/preview-api/src/modules/store/autoTitle.ts index ca810f63bbb9..c28125f65ff4 100644 --- a/code/lib/preview-api/src/modules/store/autoTitle.ts +++ b/code/lib/preview-api/src/modules/store/autoTitle.ts @@ -6,31 +6,16 @@ import type { NormalizedStoriesSpecifier } from '@storybook/types'; // FIXME: types duplicated type from `core-common', to be // removed when we remove v6 back-compat. -const stripExtension = (path: string[]) => { - let parts = [...path]; - const last = parts[parts.length - 1]; - const dotIndex = last.indexOf('.'); - const stripped = dotIndex > 0 ? last.substr(0, dotIndex) : last; - parts[parts.length - 1] = stripped; - const [first, ...rest] = parts; - if (first === '') { - parts = rest; - } - return parts; +const stripExtension = (parts: string[]) => { + const last = parts[parts.length - 1]?.replace(/(?:[.](?:story|stories))?([.][^.]+)$/i, ''); + return last ? [...parts.slice(0, -1), last] : parts; }; -const indexRe = /^index$/i; - // deal with files like "atoms/button/{button,index}.stories.js" -const removeRedundantFilename = (paths: string[]) => { - let prevVal: string; - return paths.filter((val, index) => { - if (index === paths.length - 1 && (val === prevVal || indexRe.test(val))) { - return false; - } - prevVal = val; - return true; - }); +const removeRedundantFilename = (parts: string[]) => { + const last = parts[parts.length - 1]; + const nextToLast = parts[parts.length - 2]; + return last && (last === nextToLast || /^index$/i.test(last)) ? parts.slice(0, -1) : parts; }; /** @@ -41,8 +26,10 @@ const removeRedundantFilename = (paths: string[]) => { * @returns joined path string, with single '/' between parts */ function pathJoin(paths: string[]): string { - const slashes = new RegExp('/{1,}', 'g'); - return paths.join('/').replace(slashes, '/'); + return paths + .flatMap((p) => p.split('/')) + .filter(Boolean) + .join('/'); } export const userOrAutoTitleFromSpecifier = ( @@ -67,18 +54,17 @@ export const userOrAutoTitleFromSpecifier = ( if (importPathMatcher.exec(normalizedFileName)) { if (!userTitle) { const suffix = normalizedFileName.replace(directory, ''); - const titleAndSuffix = slash(pathJoin([titlePrefix, suffix])); - let path = titleAndSuffix.split('/'); - path = stripExtension(path); - path = removeRedundantFilename(path); - return path.join('/'); + let parts = pathJoin([titlePrefix, suffix]).split('/'); + parts = stripExtension(parts); + parts = removeRedundantFilename(parts); + return parts.join('/'); } if (!titlePrefix) { return userTitle; } - return slash(pathJoin([titlePrefix, userTitle])); + return pathJoin([titlePrefix, userTitle]); } return undefined;