@storybook/addon-svelte-csf
Version:
Allows to write stories in Svelte syntax
158 lines (157 loc) • 4.9 kB
JavaScript
import { createASTArrayExpression, createASTExpressionTag, } from '../../../parser/ast.js';
/**
* Codemod to transform AST node of `<Meta>` component to `defineMeta`
*
* @example
* ```diff
* - <Meta title="Atom/Button" component={Button} args={{ ... }} />
* + const { Story } = defineMeta({
* + title: "Atom/Button",
* + component: Button,
* + args: { ... },
* + });
* ```
*/
export function transformComponentMetaToDefineMeta(params) {
const { component, comment } = params;
const { attributes, start, end } = component;
let properties = [];
for (const attribute of attributes) {
if (attribute.type === 'Attribute') {
properties.push(attributeToObjectExpressionProperty(attribute));
}
}
const firstArgument = {
type: 'ObjectExpression',
properties,
};
const key = {
type: 'Identifier',
name: 'Story',
};
return {
type: 'VariableDeclaration',
kind: 'const',
declarations: [
{
type: 'VariableDeclarator',
init: {
type: 'CallExpression',
callee: {
type: 'Identifier',
name: 'defineMeta',
},
arguments: [firstArgument],
optional: false,
},
id: {
type: 'ObjectPattern',
properties: [
{
type: 'Property',
kind: 'init',
key,
value: key,
method: false,
shorthand: true,
computed: false,
},
],
},
},
],
leadingComments: comment ? [transformMetaCommentToBlockComment(comment)] : undefined,
start,
end,
};
}
function transformMetaCommentToBlockComment(comment) {
const { data } = comment;
return {
type: 'Block',
value: `*${data.replace(/\n/, '\n* ')}`,
};
}
function attributeToObjectExpressionProperty(attribute) {
const { name } = attribute;
if (name === 'tags') {
transformTags(attribute);
}
const key = {
type: 'Identifier',
name,
};
return {
type: 'Property',
kind: 'init',
key,
value: attributeValueToPropertyValue(attribute.value),
shorthand: true,
method: false,
computed: false,
};
}
function attributeValueToPropertyValue(value) {
if (value === true) {
return {
type: 'Literal',
value: true,
};
}
if (!Array.isArray(value)) {
return value.expression;
}
if (value[0].type === 'Text') {
return {
type: 'Literal',
value: value[0].raw,
};
}
return value[0].expression;
}
function transformTags(tags) {
if (tags.value === true) {
// NOTE: The error on invalid type (boolean) is likely visible
// 1. via TypeScript
// 2. and thrown by storybook internal, right?
return;
}
// tags.value is SvelteAST.ExpressionTag
if (!Array.isArray(tags.value)) {
if (typeof tags.value.expression.value !== 'string') {
// NOTE: The error on invalid type (not a string) is likely visible
// 1. via TypeScript
// 2. and thrown by storybook internal, right?
return;
}
// NOTE: This is the only case so far where
// we need to transform tags from singular string literal to an array expression - to align with CSF3 format
tags.value.expression = createASTArrayExpression([tags.value.expression]);
return;
}
if (tags.value[0].type === 'ExpressionTag' && tags.value[0].expression.type === 'Literal') {
if (typeof tags.value[0].expression.value !== 'string') {
// NOTE: The error on invalid type (not a string) is likely visible
// 1. via TypeScript
// 2. and thrown by storybook internal, right?
return;
}
// NOTE: This is the only case so far where
// we need to transform tags from singular string literal to an array expression - to align with CSF3 format
tags.value = createASTExpressionTag(createASTArrayExpression([
{
type: 'Literal',
value: tags.value[0].data,
},
]));
return;
}
if (tags.value[0].type === 'Text') {
tags.value = createASTExpressionTag(createASTArrayExpression([
{
type: 'Literal',
value: tags.value[0].data,
},
]));
}
}