@storybook/docs-mdx
Advanced tools
+61
-14
@@ -9,9 +9,17 @@ import * as t from '@babel/types'; | ||
| const attr = elt.attributes.find(n => n.name.name === what); | ||
| return attr === null || attr === void 0 ? void 0 : attr.value; | ||
| return attr; | ||
| }; | ||
| const getAttrValue = (elt, what) => { | ||
| var _getAttr; | ||
| return (_getAttr = getAttr(elt, what)) === null || _getAttr === void 0 ? void 0 : _getAttr.value; | ||
| }; | ||
| const extractTitle = (root, varToImport) => { | ||
| const result = { | ||
| title: undefined, | ||
| of: undefined | ||
| of: undefined, | ||
| name: undefined, | ||
| isTemplate: false | ||
| }; | ||
@@ -34,22 +42,32 @@ let contents; | ||
| if (name === 'Meta') { | ||
| if (result.title) { | ||
| if (result.title || result.name || result.of) { | ||
| throw new Error('Meta can only be declared once'); | ||
| } | ||
| const titleAttr = getAttr(child.openingElement, 'title'); | ||
| const titleAttrValue = getAttrValue(child.openingElement, 'title'); | ||
| if (titleAttr) { | ||
| if (t.isStringLiteral(titleAttr)) { | ||
| result.title = titleAttr.value; | ||
| if (titleAttrValue) { | ||
| if (t.isStringLiteral(titleAttrValue)) { | ||
| result.title = titleAttrValue.value; | ||
| } else { | ||
| throw new Error(`Expected string literal title, received ${titleAttr.type}`); | ||
| throw new Error(`Expected string literal title, received ${titleAttrValue.type}`); | ||
| } | ||
| } | ||
| const ofAttr = getAttr(child.openingElement, 'of'); | ||
| const nameAttrValue = getAttrValue(child.openingElement, 'name'); | ||
| if (ofAttr) { | ||
| if (t.isJSXExpressionContainer(ofAttr)) { | ||
| const of = ofAttr.expression; | ||
| if (nameAttrValue) { | ||
| if (t.isStringLiteral(nameAttrValue)) { | ||
| result.name = nameAttrValue.value; | ||
| } else { | ||
| throw new Error(`Expected string literal name, received ${nameAttrValue.type}`); | ||
| } | ||
| } | ||
| const ofAttrValue = getAttrValue(child.openingElement, 'of'); | ||
| if (ofAttrValue) { | ||
| if (t.isJSXExpressionContainer(ofAttrValue)) { | ||
| const of = ofAttrValue.expression; | ||
| if (t.isIdentifier(of)) { | ||
@@ -67,5 +85,24 @@ const importName = varToImport[of.name]; | ||
| } else { | ||
| throw new Error(`Expected JSX expression, received ${ofAttr.type}`); | ||
| throw new Error(`Expected JSX expression, received ${ofAttrValue.type}`); | ||
| } | ||
| } | ||
| const isTemplateAttr = getAttr(child.openingElement, 'isTemplate'); | ||
| if (isTemplateAttr) { | ||
| if (!isTemplateAttr.value) { | ||
| // no value, implicit true | ||
| result.isTemplate = true; | ||
| } else if (t.isJSXExpressionContainer(isTemplateAttr.value)) { | ||
| const isTemplate = isTemplateAttr.value.expression; | ||
| if (t.isBooleanLiteral(isTemplate)) { | ||
| result.isTemplate = isTemplate.value; | ||
| } else { | ||
| throw new Error(`Expected boolean isTemplate, received ${isTemplate.type}`); | ||
| } | ||
| } else { | ||
| throw new Error(`Expected JSX expression isTemplate, received ${isTemplateAttr.value.type}`); | ||
| } | ||
| } | ||
| } | ||
@@ -159,6 +196,10 @@ } | ||
| title, | ||
| of | ||
| of, | ||
| name, | ||
| isTemplate | ||
| } = extractTitle(babel, varToImport); | ||
| store.title = title; | ||
| store.of = of; | ||
| store.name = name; | ||
| store.isTemplate = isTemplate; | ||
| store.imports = Array.from(new Set(Object.values(varToImport))); | ||
@@ -171,2 +212,4 @@ return root; | ||
| of: undefined, | ||
| name: undefined, | ||
| isTemplate: false, | ||
| imports: undefined, | ||
@@ -181,2 +224,4 @@ toEstree | ||
| of, | ||
| name, | ||
| isTemplate, | ||
| imports = [] | ||
@@ -187,4 +232,6 @@ } = store; | ||
| of, | ||
| name, | ||
| isTemplate, | ||
| imports | ||
| }; | ||
| }; |
+137
-35
@@ -10,9 +10,8 @@ import { dedent } from 'ts-dedent'; | ||
| import { Meta } from '@storybook/blocks'; | ||
| import meta, { Basic } from './Button.stories'; | ||
| import * as ButtonStories from './Button.stories'; | ||
| `); | ||
| expect(extractImports(ast)).toMatchInlineSnapshot(` | ||
| Object { | ||
| "Basic": "./Button.stories", | ||
| "ButtonStories": "./Button.stories", | ||
| "Meta": "@storybook/blocks", | ||
| "meta": "./Button.stories", | ||
| } | ||
@@ -32,2 +31,4 @@ `); | ||
| "imports": Array [], | ||
| "isTemplate": false, | ||
| "name": undefined, | ||
| "of": undefined, | ||
@@ -46,10 +47,28 @@ "title": "foobar", | ||
| }); | ||
| it('duplicate titles', () => { | ||
| }); | ||
| describe('name', () => { | ||
| it('string literal name', () => { | ||
| const input = dedent` | ||
| <Meta title="foobar" /> | ||
| # hello | ||
| <Meta title="bz" /> | ||
| <Meta name="foobar" /> | ||
| `; | ||
| expect(() => analyze(input)).toThrowErrorMatchingInlineSnapshot(`"Meta can only be declared once"`); | ||
| expect(analyze(input)).toMatchInlineSnapshot(` | ||
| Object { | ||
| "imports": Array [], | ||
| "isTemplate": false, | ||
| "name": "foobar", | ||
| "of": undefined, | ||
| "title": undefined, | ||
| } | ||
| `); | ||
| }); | ||
| it('template literal name', () => { | ||
| const input = dedent` | ||
| # hello | ||
| <Meta name={\`foobar\`} /> | ||
| `; | ||
| expect(() => analyze(input)).toThrowErrorMatchingInlineSnapshot(`"Expected string literal name, received JSXExpressionContainer"`); | ||
| }); | ||
| }); | ||
@@ -60,16 +79,18 @@ describe('of', () => { | ||
| import { Meta } from '@storybook/blocks'; | ||
| import meta, { Basic } from './Button.stories'; | ||
| import * as ButtonStories from './Button.stories'; | ||
| <Meta of={meta} /> | ||
| <Meta of={ButtonStories} /> | ||
| `; | ||
| expect(analyze(input)).toMatchInlineSnapshot(` | ||
| Object { | ||
| "imports": Array [ | ||
| "@storybook/blocks", | ||
| "./Button.stories", | ||
| ], | ||
| "of": "./Button.stories", | ||
| "title": undefined, | ||
| } | ||
| `); | ||
| Object { | ||
| "imports": Array [ | ||
| "@storybook/blocks", | ||
| "./Button.stories", | ||
| ], | ||
| "isTemplate": false, | ||
| "name": undefined, | ||
| "of": "./Button.stories", | ||
| "title": undefined, | ||
| } | ||
| `); | ||
| }); | ||
@@ -84,3 +105,3 @@ it('missing variable', () => { | ||
| const input = dedent` | ||
| import meta, { Basic } from './Button.stories'; | ||
| import * as ButtonStories from './Button.stories'; | ||
@@ -92,2 +113,61 @@ <Meta of="foobar" /> | ||
| }); | ||
| describe('isTemplate', () => { | ||
| it('boolean implicit', () => { | ||
| const input = dedent` | ||
| <Meta isTemplate /> | ||
| `; | ||
| expect(analyze(input)).toMatchInlineSnapshot(` | ||
| Object { | ||
| "imports": Array [], | ||
| "isTemplate": true, | ||
| "name": undefined, | ||
| "of": undefined, | ||
| "title": undefined, | ||
| } | ||
| `); | ||
| }); // For some reason these two tests throw with: | ||
| // "TypeError: this[node.value.type] is not a function" | ||
| // It's not clear why? | ||
| it.skip('boolean expression, true', () => { | ||
| const input = dedent` | ||
| <Meta isTemplate={true} /> | ||
| `; | ||
| expect(analyze(input)).toMatchInlineSnapshot(` | ||
| Object { | ||
| "imports": Array [], | ||
| "isTemplate": true, | ||
| "name": undefined, | ||
| "of": undefined, | ||
| "title": undefined, | ||
| } | ||
| `); | ||
| }); | ||
| it.skip('boolean expression, false', () => { | ||
| const input = dedent` | ||
| <Meta isTemplate={false} /> | ||
| `; | ||
| expect(analyze(input)).toMatchInlineSnapshot(` | ||
| Object { | ||
| "imports": Array [], | ||
| "isTemplate": false, | ||
| "name": undefined, | ||
| "of": undefined, | ||
| "title": undefined, | ||
| } | ||
| `); | ||
| }); | ||
| it('string literal', () => { | ||
| const input = dedent` | ||
| <Meta isTemplate="foo" /> | ||
| `; | ||
| expect(() => analyze(input)).toThrowErrorMatchingInlineSnapshot(`"Expected JSX expression isTemplate, received StringLiteral"`); | ||
| }); | ||
| it('other expression', () => { | ||
| const input = dedent` | ||
| <Meta isTemplate={1} /> | ||
| `; | ||
| expect(() => analyze(input)).toThrowErrorMatchingInlineSnapshot(`"Expected boolean isTemplate, received NumericLiteral"`); | ||
| }); | ||
| }); | ||
| describe('errors', () => { | ||
@@ -99,26 +179,48 @@ it('no title', () => { | ||
| expect(analyze(input)).toMatchInlineSnapshot(` | ||
| Object { | ||
| "imports": Array [], | ||
| "of": undefined, | ||
| "title": undefined, | ||
| } | ||
| `); | ||
| Object { | ||
| "imports": Array [], | ||
| "isTemplate": false, | ||
| "name": undefined, | ||
| "of": undefined, | ||
| "title": undefined, | ||
| } | ||
| `); | ||
| }); | ||
| it('Bad MDX formatting', () => { | ||
| const input = dedent` | ||
| import meta, { Basic } from './Button.stories'; | ||
| import * as ButtonStories from './Button.stories'; | ||
| <Meta of={meta} />/> | ||
| <Meta of={ButtonStories} />/> | ||
| `; | ||
| expect(analyze(input)).toMatchInlineSnapshot(` | ||
| Object { | ||
| "imports": Array [ | ||
| "./Button.stories", | ||
| ], | ||
| "of": undefined, | ||
| "title": undefined, | ||
| } | ||
| `); | ||
| Object { | ||
| "imports": Array [ | ||
| "./Button.stories", | ||
| ], | ||
| "isTemplate": false, | ||
| "name": undefined, | ||
| "of": undefined, | ||
| "title": undefined, | ||
| } | ||
| `); | ||
| }); | ||
| it('duplicate meta, both title', () => { | ||
| const input = dedent` | ||
| <Meta title="foobar" /> | ||
| <Meta title="bz" /> | ||
| `; | ||
| expect(() => analyze(input)).toThrowErrorMatchingInlineSnapshot(`"Meta can only be declared once"`); | ||
| }); | ||
| it('duplicate meta, different', () => { | ||
| const input = dedent` | ||
| import * as ButtonStories from './Button.stories'; | ||
| <Meta title="foobar" /> | ||
| <Meta of={ButtonStories} /> | ||
| `; | ||
| expect(() => analyze(input)).toThrowErrorMatchingInlineSnapshot(`"Meta can only be declared once"`); | ||
| }); | ||
| }); | ||
| }); |
@@ -7,3 +7,5 @@ import * as t from '@babel/types'; | ||
| of: any; | ||
| name: any; | ||
| isTemplate: any; | ||
| imports: any; | ||
| }; |
+4
-4
| { | ||
| "name": "@storybook/docs-mdx", | ||
| "version": "0.0.1-canary.2.197a63f.0", | ||
| "version": "0.0.1-canary.12433cf.0", | ||
| "description": "Storybook Docs MDX analyzer", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/storybookjs/docs-mdx" | ||
| "url": "https://github.com/storybookjs/docs2-mdx" | ||
| }, | ||
@@ -12,3 +12,4 @@ "author": "Michael Shilman <michael@lab80.co>", | ||
| "type": "module", | ||
| "main": "index", | ||
| "main": "index.cjs", | ||
| "module": "dist/esm/index.js", | ||
| "types": "dist/ts/index.d.ts", | ||
@@ -20,3 +21,2 @@ "files": [ | ||
| "*.d.ts", | ||
| "index.mjs", | ||
| "index.cjs" | ||
@@ -23,0 +23,0 @@ ], |
| export default import('./dist/esm/index.js'); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
16797
32.37%418
49.29%0
-100%10
-9.09%