Skip to content

Commit

Permalink
fix: handle button.group.stories.js in auto-title
Browse files Browse the repository at this point in the history
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().
  • Loading branch information
agriffis committed Sep 20, 2023
1 parent 1a0d84f commit 42a35ae
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 30 deletions.
10 changes: 10 additions & 0 deletions code/lib/preview-api/src/modules/store/autoTitle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
46 changes: 16 additions & 30 deletions code/lib/preview-api/src/modules/store/autoTitle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

/**
Expand All @@ -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 = (
Expand All @@ -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;
Expand Down

0 comments on commit 42a35ae

Please sign in to comment.