Skip to content

Commit

Permalink
CSF plugin: Turn story comments into docs desciptions
Browse files Browse the repository at this point in the history
  • Loading branch information
shilman committed Oct 29, 2022
1 parent 96ca5a9 commit 0ba7eaa
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 9 deletions.
1 change: 0 additions & 1 deletion code/lib/csf-tools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
"devDependencies": {
"@babel/generator": "^7.12.11",
"@babel/parser": "^7.12.11",
"@babel/template": "^7.12.11",
"@babel/traverse": "^7.12.11",
"@types/fs-extra": "^9.0.6",
"js-yaml": "^3.14.1",
Expand Down
3 changes: 3 additions & 0 deletions code/lib/csf-tools/src/CsfFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ export class CsfFile {

_storyExports: Record<string, t.VariableDeclarator | t.FunctionDeclaration> = {};

_storyStatements: Record<string, t.ExportNamedDeclaration> = {};

_storyAnnotations: Record<string, Record<string, t.Node>> = {};

_templates: Record<string, t.Expression> = {};
Expand Down Expand Up @@ -283,6 +285,7 @@ export class CsfFile {
return;
}
self._storyExports[exportName] = decl;
self._storyStatements[exportName] = node;
let name = storyNameFromExport(exportName);
if (self._storyAnnotations[exportName]) {
logger.warn(
Expand Down
116 changes: 116 additions & 0 deletions code/lib/csf-tools/src/enrichCsf.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,122 @@ describe('enrichCsf', () => {
`);
});
});

describe('descriptions', () => {
it('skips inline comments', () => {
expect(
enrich(dedent`
export default {
title: 'Button',
}
// The most basic button
export const Basic = () => <Button />
`)
).toMatchInlineSnapshot(`
export default {
title: 'Button'
};
// The most basic button
export const Basic = () => <Button />;
Basic.parameters = {
storySource: {
source: "() => <Button />"
},
...Basic.parameters
};
`);
});

it('skips blocks without jsdoc', () => {
expect(
enrich(dedent`
export default {
title: 'Button',
}
/* The most basic button */
export const Basic = () => <Button />
`)
).toMatchInlineSnapshot(`
export default {
title: 'Button'
};
/* The most basic button */
export const Basic = () => <Button />;
Basic.parameters = {
storySource: {
source: "() => <Button />"
},
...Basic.parameters
};
`);
});

it('JSDoc single-line', () => {
expect(
enrich(dedent`
export default {
title: 'Button',
}
/** The most basic button */
export const Basic = () => <Button />
`)
).toMatchInlineSnapshot(`
export default {
title: 'Button'
};
/** The most basic button */
export const Basic = () => <Button />;
Basic.parameters = {
storySource: {
source: "() => <Button />"
},
docs: {
description: {
story: "The most basic button"
}
},
...Basic.parameters
};
`);
});

it('JSDoc multi-line', () => {
expect(
enrich(dedent`
export default {
title: 'Button',
}
/**
* The most basic button
*
* In a block!
*/
export const Basic = () => <Button />
`)
).toMatchInlineSnapshot(`
export default {
title: 'Button'
};
/**
* The most basic button
*
* In a block!
*/
export const Basic = () => <Button />;
Basic.parameters = {
storySource: {
source: "() => <Button />"
},
docs: {
description: {
story: "The most basic button\\n\\nIn a block!"
}
},
...Basic.parameters
};
`);
});
});
});

const source = (csfExport: string) => {
Expand Down
55 changes: 47 additions & 8 deletions code/lib/csf-tools/src/enrichCsf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,42 @@
import * as t from '@babel/types';
// eslint-disable-next-line import/no-extraneous-dependencies
import * as generate from '@babel/generator';
// eslint-disable-next-line import/no-extraneous-dependencies
import * as template from '@babel/template';
import type { CsfFile } from './CsfFile';

export const enrichCsf = (csf: CsfFile) => {
Object.keys(csf._storyExports).forEach((key) => {
const storyExport = csf.getStoryExport(key);
const source = extractSource(storyExport);
const addParameter = template.default(`
%%key%%.parameters = { storySource: { source: %%source%% }, ...%%key%%.parameters };
`)({
key: t.identifier(key),
source: t.stringLiteral(source),
}) as t.Statement;
const description = extractDescription(csf._storyStatements[key]);
const parameters = [];
// storySource: { source: %%source%% },
parameters.push(
t.objectProperty(
t.identifier('storySource'),
t.objectExpression([t.objectProperty(t.identifier('source'), t.stringLiteral(source))])
)
);
// docs: { description: { story: %%description%% } },
if (description) {
parameters.push(
t.objectProperty(
t.identifier('docs'),
t.objectExpression([
t.objectProperty(
t.identifier('description'),
t.objectExpression([
t.objectProperty(t.identifier('story'), t.stringLiteral(description)),
])
),
])
)
);
}
const originalParameters = t.memberExpression(t.identifier(key), t.identifier('parameters'));
parameters.push(t.spreadElement(originalParameters));
const addParameter = t.expressionStatement(
t.assignmentExpression('=', originalParameters, t.objectExpression(parameters))
);
csf._ast.program.body.push(addParameter);
});
};
Expand All @@ -25,3 +47,20 @@ export const extractSource = (node: t.Node) => {
const { code } = generate.default(src, {});
return code;
};

export const extractDescription = (node?: t.Node) => {
if (node?.leadingComments) {
const comments = node.leadingComments
.map((comment) => {
if (comment.type === 'CommentLine' || !comment.value.startsWith('*')) return null;
return comment.value
.split('\n')
.map((line) => line.replace(/^(\s+)?(\*+)?(\s+)?/, ''))
.join('\n')
.trim();
})
.filter(Boolean);
return comments.join('\n');
}
return '';
};

0 comments on commit 0ba7eaa

Please sign in to comment.