UNPKG

@storybook/addon-svelte-csf

Version:
161 lines (160 loc) 5.35 kB
import dedent from 'dedent'; import { getDefineMetaComponentValue } from '../define-meta/component-identifier.js'; import { extractStoryTemplateSnippetBlock } from '../../extract/svelte/story/template.js'; import { findMetaRenderSnippetBlock, findStoryAttributeTemplateSnippetBlock, } from '../../extract/svelte/snippet-block.js'; import { extractStoryAttributesNodes } from '../../extract/svelte/story/attributes.js'; /** * Extract the source code of the `<Story />` component content (children or template snippet). * Reference: Step 2 from the comment: https://github.com/storybookjs/addon-svelte-csf/pull/181#issuecomment-2143539873 */ export function getStoryContentRawCode(params) { const { nodes, originalCode, filename } = params; const { component, svelte } = nodes; // `<Story />` component is self-closing... if (component.fragment.nodes.length === 0) { /** * Case - "explicit template" - `template` attribute references to a snippet block at the root level of fragment. * * Example: * * ```svelte * {#snippet template1(args)} * <SomeComponent {...args} /> * {/snippet} * * <Story name="Default" template={template1} /> * ``` */ const storyAttributTemplateSnippetBlock = findStoryAttributeTemplateSnippetBlock({ component, nodes: svelte, filename, }); if (storyAttributTemplateSnippetBlock) { return getSnippetBlockBodyRawCode(originalCode, storyAttributTemplateSnippetBlock); } /** * Case - `render` was set in `defineMeta` * * Example: * * ```svelte * <script module> * import { defineMeta } from "@storybook/addon-svelte-csf"; * * const { Story } = defineMeta({ * render: myCustomTemplate, * }); * </script> * * {#snippet myCustomTemplate(args)} * <SomeComponent {...args} /> * {/snippet} * * <Story name="Default" /> * ``` */ const metaRenderSnippetBlock = findMetaRenderSnippetBlock({ nodes: svelte, filename, }); if (metaRenderSnippetBlock) { return getSnippetBlockBodyRawCode(originalCode, metaRenderSnippetBlock); } /* Case - No `children` attribute provided, no `render` used, just a Story */ const defineMetaComponentValue = getDefineMetaComponentValue({ nodes: svelte, filename, }); // NOTE: It should never be `undefined` in this particular case, otherwise Storybook wouldn't know what to render. return `<${defineMetaComponentValue?.name} {...args} />`; } /** * Case - Story with children - and with a snippet block `template` inside * * Example: * * ```svelte * <Story name="Default"> * {#snippet template(args)} * <SomeComponent {...args} /> * {/snippet} * </Story> * ``` */ const storyChildrenSnippetBlock = extractStoryTemplateSnippetBlock(component); if (storyChildrenSnippetBlock) { return getSnippetBlockBodyRawCode(originalCode, storyChildrenSnippetBlock); } /** * Case - Inner children used directly with `asChild` attribute * * Example: * * ```svelte * <Story name="Default" asChild> * <SomeComponent foo="bar" /> * </Story> * ``` */ const { asChild } = extractStoryAttributesNodes({ component, attributes: ['asChild'], }); const { fragment } = component; const firstNode = fragment.nodes[0]; const lastNode = fragment.nodes[fragment.nodes.length - 1]; const rawCode = dedent(originalCode.slice(firstNode.start, lastNode.end)); if (asChild) { return rawCode; } /** * Case - `children` provided as prop to component or template * * Example: * * ```svelte * <Story name="Default"> * <SomeComponent foo="bar" /> * </Story> * ``` */ const defineMetaComponentValue = getDefineMetaComponentValue({ nodes: svelte, filename, }); // NOTE: It should never be `undefined` in this particular case, otherwise Storybook wouldn't know what to render. return dedent(`<${defineMetaComponentValue?.name} {...args}> ${rawCode} </${defineMetaComponentValue?.name}>`); } /** * Extract from the original code a string slice with the body of the svelte's snippet block. * Starting from the start of the first node, and ending with the end of the last node. * * For example, from the following case: * * ```svelte * {#snippet template(args)} * <!-- Some comment... --> * "Static text" * <Component {...args } /> * {/snippet} * ``` * * The result would be: * * ```txt * <!-- Some comment... --> * "Static text" * <Component {...args } /> * ``` */ function getSnippetBlockBodyRawCode(originalCode, node) { const { body } = node; const { nodes } = body; const firstNode = nodes[0]; const lastNode = nodes[nodes.length - 1]; const rawCode = originalCode.slice(firstNode.start, lastNode.end); return dedent(rawCode); }