mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-04 13:01:07 +08:00
Merge pull request #12107 from storybookjs/12054-fix-mdx-source-for-template
Addon-docs: Fix source code for Template.bind({}) in MDX
This commit is contained in:
commit
8ba6c97973
@ -65,7 +65,7 @@ componentNotes.args = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
componentNotes.parameters = { storySource: { source: 'Template.bind({})' } };
|
||||
componentNotes.parameters = { storySource: { source: 'args => <Button>Component notes</Button>' } };
|
||||
|
||||
const componentMeta = { title: 'Button', includeStories: ['componentNotes'] };
|
||||
|
||||
|
@ -71,6 +71,32 @@ function genImportStory(ast, storyDef, storyName, context) {
|
||||
};
|
||||
}
|
||||
|
||||
function getBodyPart(bodyNode, context) {
|
||||
const body = bodyNode.type === 'JSXExpressionContainer' ? bodyNode.expression : bodyNode;
|
||||
let sourceBody = body;
|
||||
if (
|
||||
body.type === 'CallExpression' &&
|
||||
body.callee.type === 'MemberExpression' &&
|
||||
body.callee.object.type === 'Identifier' &&
|
||||
body.callee.property.type === 'Identifier' &&
|
||||
body.callee.property.name === 'bind' &&
|
||||
(body.arguments.length === 0 ||
|
||||
(body.arguments.length === 1 &&
|
||||
body.arguments[0].type === 'ObjectExpression' &&
|
||||
body.arguments[0].properties.length === 0))
|
||||
) {
|
||||
const bound = body.callee.object.name;
|
||||
const namedExport = context.namedExports[bound];
|
||||
if (namedExport) {
|
||||
sourceBody = namedExport;
|
||||
}
|
||||
}
|
||||
|
||||
const { code: storyCode } = generate(body, {});
|
||||
const { code: sourceCode } = generate(sourceBody, {});
|
||||
return { storyCode, sourceCode, body };
|
||||
}
|
||||
|
||||
function genStoryExport(ast, context) {
|
||||
let storyName = getAttr(ast.openingElement, 'name');
|
||||
let storyId = getAttr(ast.openingElement, 'id');
|
||||
@ -96,30 +122,29 @@ function genStoryExport(ast, context) {
|
||||
|
||||
const bodyNodes = ast.children.filter((n) => n.type !== 'JSXText');
|
||||
let storyCode = null;
|
||||
let sourceCode = null;
|
||||
let storyVal = null;
|
||||
if (!bodyNodes.length) {
|
||||
// plain text node
|
||||
const { code } = generate(ast.children[0], {});
|
||||
storyCode = `'${code}'`;
|
||||
sourceCode = storyCode;
|
||||
storyVal = `() => (
|
||||
${storyCode}
|
||||
)`;
|
||||
} else {
|
||||
const bodyParts = bodyNodes.map((bodyNode) => {
|
||||
const body = bodyNode.type === 'JSXExpressionContainer' ? bodyNode.expression : bodyNode;
|
||||
const { code } = generate(body, {});
|
||||
return { code, body };
|
||||
});
|
||||
const bodyParts = bodyNodes.map((bodyNode) => getBodyPart(bodyNode, context));
|
||||
// if we have more than two children
|
||||
// 1. Add line breaks
|
||||
// 2. Enclose in <> ... </>
|
||||
storyCode = bodyParts.map(({ code }) => code).join('\n');
|
||||
storyCode = bodyParts.map(({ storyCode: code }) => code).join('\n');
|
||||
sourceCode = bodyParts.map(({ sourceCode: code }) => code).join('\n');
|
||||
const storyReactCode = bodyParts.length > 1 ? `<>\n${storyCode}\n</>` : storyCode;
|
||||
// keep track if an indentifier or function call
|
||||
// avoid breaking change for 5.3
|
||||
const BIND_REGEX = /\.bind\(.*\)/;
|
||||
if (bodyParts.length === 1 && BIND_REGEX.test(bodyParts[0].code)) {
|
||||
storyVal = bodyParts[0].code;
|
||||
if (bodyParts.length === 1 && BIND_REGEX.test(bodyParts[0].storyCode)) {
|
||||
storyVal = bodyParts[0].storyCode;
|
||||
} else {
|
||||
switch (bodyParts.length === 1 && bodyParts[0].body.type) {
|
||||
// We don't know what type the identifier is, but this code
|
||||
@ -152,7 +177,7 @@ function genStoryExport(ast, context) {
|
||||
|
||||
let parameters = getAttr(ast.openingElement, 'parameters');
|
||||
parameters = parameters && parameters.expression;
|
||||
const source = jsStringEscape(storyCode);
|
||||
const source = jsStringEscape(sourceCode);
|
||||
const sourceParam = `storySource: { source: '${source}' }`;
|
||||
if (parameters) {
|
||||
const { code: params } = generate(parameters, {});
|
||||
@ -252,10 +277,13 @@ function getExports(node, counter, options) {
|
||||
|
||||
const canvasExports = genCanvasExports(ast, counter);
|
||||
|
||||
// We're overwriting the Canvas tag here with a version that
|
||||
// has the `name` attribute (e.g. `<Story name="..." story={...} />`)
|
||||
// even if the user didn't provide one. We need the name attribute when
|
||||
// we render the node at runtime.
|
||||
const { code } = generate(ast, {});
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
node.value = code;
|
||||
|
||||
return { stories: canvasExports };
|
||||
}
|
||||
if (META_REGEX.exec(value)) {
|
||||
@ -300,8 +328,48 @@ const hasStoryChild = (node) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
function extractExports(node, options) {
|
||||
node.children.forEach((child) => {
|
||||
const getMdxSource = (children) =>
|
||||
encodeURI(
|
||||
children
|
||||
.map(
|
||||
(el) =>
|
||||
generate(el, {
|
||||
quotes: 'double',
|
||||
}).code
|
||||
)
|
||||
.join('\n')
|
||||
);
|
||||
|
||||
// Parse out the named exports from a node, where the key
|
||||
// is the variable name and the value is the AST of the
|
||||
// variable declaration initializer
|
||||
const getNamedExports = (node) => {
|
||||
const namedExports = {};
|
||||
const ast = parser.parse(node.value, {
|
||||
sourceType: 'module',
|
||||
presets: ['env'],
|
||||
plugins: ['jsx'],
|
||||
});
|
||||
if (ast.type === 'File' && ast.program.type === 'Program' && ast.program.body.length === 1) {
|
||||
const exported = ast.program.body[0];
|
||||
if (
|
||||
exported.type === 'ExportNamedDeclaration' &&
|
||||
exported.declaration.type === 'VariableDeclaration' &&
|
||||
exported.declaration.declarations.length === 1
|
||||
) {
|
||||
const declaration = exported.declaration.declarations[0];
|
||||
if (declaration.type === 'VariableDeclarator' && declaration.id.type === 'Identifier') {
|
||||
const { name } = declaration.id;
|
||||
namedExports[name] = declaration.init;
|
||||
}
|
||||
}
|
||||
}
|
||||
return namedExports;
|
||||
};
|
||||
|
||||
function extractExports(root, options) {
|
||||
const namedExports = {};
|
||||
root.children.forEach((child) => {
|
||||
if (child.type === 'jsx') {
|
||||
try {
|
||||
const ast = parser.parseExpression(child.value, { plugins: ['jsx'] });
|
||||
@ -320,16 +388,7 @@ function extractExports(node, options) {
|
||||
},
|
||||
value: {
|
||||
type: 'StringLiteral',
|
||||
value: encodeURI(
|
||||
ast.children
|
||||
.map(
|
||||
(el) =>
|
||||
generate(el, {
|
||||
quotes: 'double',
|
||||
}).code
|
||||
)
|
||||
.join('\n')
|
||||
),
|
||||
value: getMdxSource(ast.children),
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -350,6 +409,8 @@ function extractExports(node, options) {
|
||||
*
|
||||
*/
|
||||
}
|
||||
} else if (child.type === 'export') {
|
||||
Object.assign(namedExports, getNamedExports(child));
|
||||
}
|
||||
});
|
||||
// we're overriding default export
|
||||
@ -359,8 +420,10 @@ function extractExports(node, options) {
|
||||
const context = {
|
||||
counter: 0,
|
||||
storyNameToKey: {},
|
||||
root,
|
||||
namedExports,
|
||||
};
|
||||
node.children.forEach((n) => {
|
||||
root.children.forEach((n) => {
|
||||
const exports = getExports(n, context, options);
|
||||
if (exports) {
|
||||
const { stories, meta } = exports;
|
||||
@ -389,7 +452,7 @@ function extractExports(node, options) {
|
||||
}
|
||||
metaExport.includeStories = JSON.stringify(includeStories);
|
||||
|
||||
const defaultJsx = mdxToJsx.toJSX(node, {}, { ...options, skipExport: true });
|
||||
const defaultJsx = mdxToJsx.toJSX(root, {}, { ...options, skipExport: true });
|
||||
const fullJsx = [
|
||||
'import { assertIsFn, AddContext } from "@storybook/addon-docs/blocks";',
|
||||
defaultJsx,
|
||||
@ -405,7 +468,7 @@ function extractExports(node, options) {
|
||||
|
||||
function createCompiler(mdxOptions) {
|
||||
return function compiler(options = {}) {
|
||||
this.Compiler = (tree) => extractExports(tree, options, mdxOptions);
|
||||
this.Compiler = (root) => extractExports(root, options, mdxOptions);
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user