diff --git a/code/core/src/csf-tools/CsfFile.test.ts b/code/core/src/csf-tools/CsfFile.test.ts index 17487fea5750..bb28aa11766f 100644 --- a/code/core/src/csf-tools/CsfFile.test.ts +++ b/code/core/src/csf-tools/CsfFile.test.ts @@ -1423,6 +1423,40 @@ describe('CsfFile', () => { `); }); + it('Object export with args render method', () => { + expect( + parse( + dedent` + export default { title: 'foo/bar' }; + export const A = { + render(args) {} + } + `, + true + ) + ).toMatchInlineSnapshot(` + meta: + title: foo/bar + stories: + - id: foo-bar--a + name: A + parameters: + __isArgsStory: true + __id: foo-bar--a + __stats: + factory: false + play: false + render: true + loaders: false + beforeEach: false + globals: false + tags: false + storyFn: false + mount: false + moduleMock: false + `); + }); + it('Object export with default render', () => { expect( parse( @@ -1788,6 +1822,67 @@ describe('CsfFile', () => { `); }); + it('play method', () => { + expect( + parse( + dedent` + export default { title: 'foo/bar' }; + export const A = { + play({ context }) {}, + }; + ` + ) + ).toMatchInlineSnapshot(` + meta: + title: foo/bar + stories: + - id: foo-bar--a + name: A + __stats: + factory: false + play: true + render: false + loaders: false + beforeEach: false + globals: false + tags: false + storyFn: false + mount: false + moduleMock: false + tags: + - play-fn + `); + }); + + it('meta play method', () => { + expect( + parse( + dedent` + export default { title: 'foo/bar', play({ context }) {} }; + export const A = {};` + ) + ).toMatchInlineSnapshot(` + meta: + title: foo/bar + tags: + - play-fn + stories: + - id: foo-bar--a + name: A + __stats: + factory: false + play: true + render: false + loaders: false + beforeEach: false + globals: false + tags: false + storyFn: false + mount: false + moduleMock: false + `); + }); + it('mount', () => { expect( parse( @@ -1852,6 +1947,38 @@ describe('CsfFile', () => { `); }); + it('mount in method', () => { + expect( + parse( + dedent` + export default { title: 'foo/bar' }; + export const A = { + play({ mount, context }) {}, + }; + ` + ) + ).toMatchInlineSnapshot(` + meta: + title: foo/bar + stories: + - id: foo-bar--a + name: A + __stats: + factory: false + play: true + render: false + loaders: false + beforeEach: false + globals: false + tags: false + storyFn: false + mount: true + moduleMock: false + tags: + - play-fn + `); + }); + it('mount meta', () => { expect( parse( diff --git a/code/core/src/csf-tools/CsfFile.ts b/code/core/src/csf-tools/CsfFile.ts index 213bcf2fd53e..ae93c62afa2d 100644 --- a/code/core/src/csf-tools/CsfFile.ts +++ b/code/core/src/csf-tools/CsfFile.ts @@ -175,7 +175,11 @@ const sortExports = (exportByName: Record, order: string[]) => { }; const hasMount = (play: t.Node | undefined) => { - if (t.isArrowFunctionExpression(play) || t.isFunctionDeclaration(play)) { + if ( + t.isArrowFunctionExpression(play) || + t.isFunctionDeclaration(play) || + t.isObjectMethod(play) + ) { const params = play.params; if (params.length >= 1) { const [arg] = params; @@ -348,7 +352,8 @@ export class CsfFile { const meta: StaticMeta = {}; (declaration.properties as t.ObjectProperty[]).forEach((p) => { if (t.isIdentifier(p.key)) { - this._metaAnnotations[p.key.name] = p.value; + const value = t.isObjectMethod(p) ? p : p.value; + this._metaAnnotations[p.key.name] = value; if (p.key.name === 'title') { meta.title = this._parseTitle(p.value); @@ -598,30 +603,35 @@ export class CsfFile { // CSF3 object export (storyNode.properties as t.ObjectProperty[]).forEach((p) => { if (t.isIdentifier(p.key)) { - if (p.key.name === 'render') { - parameters.__isArgsStory = isArgsStory( - p.value as t.Expression, - parent, - self - ); - } else if (p.key.name === 'name' && t.isStringLiteral(p.value)) { - name = p.value.value; - } else if (p.key.name === 'storyName' && t.isStringLiteral(p.value)) { - logger.warn( - `Unexpected usage of "storyName" in "${exportName}". Please use "name" instead.` - ); - } else if (p.key.name === 'parameters' && t.isObjectExpression(p.value)) { - const idProperty = p.value.properties.find( - (property) => - t.isObjectProperty(property) && - t.isIdentifier(property.key) && - property.key.name === '__id' - ) as t.ObjectProperty | undefined; - if (idProperty) { - parameters.__id = (idProperty.value as t.StringLiteral).value; + const key = p.key.name; + if (t.isObjectMethod(p)) { + self._storyAnnotations[exportName][key] = p; + } else { + if (p.key.name === 'render') { + parameters.__isArgsStory = isArgsStory( + p.value as t.Expression, + parent, + self + ); + } else if (p.key.name === 'name' && t.isStringLiteral(p.value)) { + name = p.value.value; + } else if (p.key.name === 'storyName' && t.isStringLiteral(p.value)) { + logger.warn( + `Unexpected usage of "storyName" in "${exportName}". Please use "name" instead.` + ); + } else if (p.key.name === 'parameters' && t.isObjectExpression(p.value)) { + const idProperty = p.value.properties.find( + (property) => + t.isObjectProperty(property) && + t.isIdentifier(property.key) && + property.key.name === '__id' + ) as t.ObjectProperty | undefined; + if (idProperty) { + parameters.__id = (idProperty.value as t.StringLiteral).value; + } } + self._storyAnnotations[exportName][p.key.name] = p.value; } - self._storyAnnotations[exportName][p.key.name] = p.value; } }); } else {