diff --git a/code/lib/eslint-plugin/docs/rules/only-csf3.md b/code/lib/eslint-plugin/docs/rules/only-csf3.md new file mode 100644 index 000000000000..6077469069af --- /dev/null +++ b/code/lib/eslint-plugin/docs/rules/only-csf3.md @@ -0,0 +1,151 @@ +# Enforce CSF3 format for stories (only-csf3) + +[Component Story Format 3.0 (CSF3)](https://storybook.js.org/blog/component-story-format-3-0/) is the latest iteration of Storybook's story format, offering a simpler and more maintainable way to write stories. This rule enforces the use of CSF3 by identifying and reporting CSF2 patterns. + + + +**Included in these configurations**: N/A + + + +## Rule Details + +This rule aims to prevent the use of CSF2 patterns in story files and encourage migration to CSF3. + +Examples of **incorrect** code: + +```js +// ❌ CSF2: Using Template.bind({}) +const Template = (args) => ; + +// ❌ CSF2: Story with property assignments +export const WithArgs = Template.bind({}); +WithArgs.args = { label: 'With Args' }; +WithArgs.parameters = { layout: 'centered' }; + +// ❌ CSF2: Template.bind({}) with multiple stories +const Template = (args) => , +}; + +// ✅ CSF3: Multiple stories sharing render logic +const render = (args) => ; +} + +// ✅ CSF3 +export const Primary = { + render: (args) => , +}; +``` + +3. Story with multiple properties: + +```js +// ❌ CSF2 +export const Primary = Template.bind({}); +Primary.args = { label: 'Primary' }; +Primary.parameters = { layout: 'centered' }; +Primary.decorators = [ + (Story) => ( +
+ +
+ ), +]; + +// ✅ CSF3 +export const Primary = { + render: (args) => + } + `, + output: dedent` + export const Secondary = { + render: function(args) { + return + }, + } + `, + errors: [ + { + messageId: 'noCSF2Format', + data: { + storyName: 'Secondary', + pattern: 'function expression', + }, + type: AST_NODE_TYPES.FunctionExpression, + }, + ], + }, + + // CSF2: Mixed with CSF3 (should detect both) + { + code: dedent` + export const Valid = { + args: { label: 'Valid' }, + } + export function Invalid(args) { + return