Skip to content

Commit

Permalink
Core: Fix sorting by __namedExportsOrder
Browse files Browse the repository at this point in the history
  • Loading branch information
shilman committed Nov 7, 2021
1 parent 8fc84eb commit 605c952
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 4 deletions.
11 changes: 11 additions & 0 deletions examples/react-ts/src/button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export default {

export const WithArgs: ComponentStory<typeof Button> = (args) => <Button {...args} />;
WithArgs.args = { label: 'With args' };

export const Basic = () => <Button label="Click me" />;

export const StoryObject = {
Expand All @@ -36,3 +37,13 @@ CSF2StoryWithPlay.play = () => {
console.log('play!!');
userEvent.click(screen.getByRole('button'));
};

// eslint-disable-next-line no-underscore-dangle
export const __namedExportsOrder = [
'Basic',
'WithArgs',
'StoryObject',
'StoryNoRender',
'StoryWithPlay',
'CSF2StoryWithPlay',
];
15 changes: 14 additions & 1 deletion lib/client-api/src/StoryStoreFacade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,20 @@ export class StoryStoreFacade<TFramework extends AnyFramework> {
default: { ...defaultExport, title },
};

Object.entries(namedExports)
let sortedExports = namedExports;

// prefer a user/loader provided `__namedExportsOrder` array if supplied
// we do this as es module exports are always ordered alphabetically
// see https://github.com/storybookjs/storybook/issues/9136
if (Array.isArray(__namedExportsOrder)) {
sortedExports = {};
__namedExportsOrder.forEach((name) => {
const namedExport = namedExports[name];
if (namedExport) sortedExports[name] = namedExport;
});
}

Object.entries(sortedExports)
.filter(([key]) => isExportStory(key, defaultExport))
.forEach(([key, storyExport]: [string, any]) => {
const exportName = storyNameFromExport(key);
Expand Down
31 changes: 31 additions & 0 deletions lib/csf-tools/src/CsfFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,34 @@ describe('CsfFile', () => {
name: B
`);
});

it('named exports order', () => {
expect(
parse(
dedent`
export default { title: 'foo/bar' };
export const A = () => {};
export const B = (args) => {};
export const __namedExportsOrder = ['B', 'A'];
`,
true
)
).toMatchInlineSnapshot(`
meta:
title: foo/bar
stories:
- id: foo-bar--b
name: B
parameters:
__isArgsStory: true
__id: foo-bar--b
- id: foo-bar--a
name: A
parameters:
__isArgsStory: false
__id: foo-bar--a
`);
});
});

describe('error handling', () => {
Expand All @@ -318,6 +346,7 @@ describe('CsfFile', () => {
)
).toThrow('CSF: missing default export');
});

it('no metadata', () => {
expect(() =>
parse(
Expand All @@ -329,6 +358,7 @@ describe('CsfFile', () => {
)
).toThrow('CSF: missing title/component');
});

it('dynamic titles', () => {
expect(() =>
parse(
Expand All @@ -340,6 +370,7 @@ describe('CsfFile', () => {
)
).toThrow('CSF: unexpected dynamic title');
});

it('storiesOf calls', () => {
expect(() =>
parse(
Expand Down
31 changes: 31 additions & 0 deletions lib/csf-tools/src/CsfFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,26 @@ const isArgsStory = (init: t.Expression, parent: t.Node, csf: CsfFile) => {
return false;
};

const parseExportsOrder = (init: t.Expression) => {
if (t.isArrayExpression(init)) {
return init.elements.map((item: t.Expression) => {
if (t.isStringLiteral(item)) {
return item.value;
}
throw new Error(`Expected string literal named export: ${item}`);
});
}
throw new Error(`Expected array of string literals: ${init}`);
};

const sortExports = (exportByName: Record<string, any>, order: string[]) => {
return order.reduce((acc, name) => {
const namedExport = exportByName[name];
if (namedExport) acc[name] = namedExport;
return acc;
}, {} as Record<string, any>);
};

export interface CsfOptions {
defaultTitle: string;
fileName?: string;
Expand Down Expand Up @@ -134,6 +154,8 @@ export class CsfFile {

_templates: Record<string, t.Expression> = {};

_namedExportsOrder?: string[];

constructor(ast: t.File, { defaultTitle, fileName }: CsfOptions) {
this._ast = ast;
this._defaultTitle = defaultTitle;
Expand Down Expand Up @@ -207,6 +229,10 @@ export class CsfFile {
node.declaration.declarations.forEach((decl) => {
if (t.isVariableDeclarator(decl) && t.isIdentifier(decl.id)) {
const { name: exportName } = decl.id;
if (exportName === '__namedExportsOrder') {
self._namedExportsOrder = parseExportsOrder(decl.init);
return;
}
self._storyExports[exportName] = decl;
let name = storyNameFromExport(exportName);
if (self._storyAnnotations[exportName]) {
Expand Down Expand Up @@ -344,6 +370,11 @@ export class CsfFile {
}
});

if (self._namedExportsOrder) {
self._storyExports = sortExports(self._storyExports, self._namedExportsOrder);
self._stories = sortExports(self._stories, self._namedExportsOrder);
}

return self;
}

Expand Down
5 changes: 2 additions & 3 deletions lib/store/src/processCSFFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,8 @@ export function processCSFFile<TFramework extends AnyFramework>(
if (Array.isArray(__namedExportsOrder)) {
exports = {};
__namedExportsOrder.forEach((name) => {
if (namedExports[name]) {
exports[name] = namedExports[name];
}
const namedExport = namedExports[name];
if (namedExport) exports[name] = namedExport;
});
}

Expand Down

0 comments on commit 605c952

Please sign in to comment.