diff --git a/addons/docs/README.md b/addons/docs/README.md index 5946e6cc71d3..57252453dc0d 100644 --- a/addons/docs/README.md +++ b/addons/docs/README.md @@ -1,3 +1,88 @@ # Storybook Docs Living documentation for your components. + +- [Sneak peak article](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) +- [Technical preview guide](https://docs.google.com/document/d/1un6YX7xDKEKl5-MVb-egnOYN8dynb5Hf7mq0hipk8JE/edit?usp=sharing) + +## View layer support + +Docs supports all view layers that Storybook supports except for React Native (currently). There are some view-layer specific +features as well. This chart captures the current state of support + +| | React | Vue | Angular | Polymer | Mithril | HTML | Marko | Svelte | Riot | Ember | Preact | +| -------------- | :---: | :-: | :-----: | :-----: | :-----: | :--: | :---: | :----: | :--: | :---: | :----: | +| MDX stories | + | + | + | + | + | + | + | + | + | + | + | +| Module stories | + | + | + | + | + | + | + | + | + | + | + | +| Legacy stories | + | + | + | + | + | + | + | + | + | + | + | +| Source \* | + | + | + | + | + | + | + | + | + | + | + | +| Notes / Info | + | + | + | + | + | + | + | + | + | + | + | +| Props table | + | # | # | | | | | | | | | +| Docgen | + | # | # | | | | | | | | | +| Inline stories | + | # | | | | | | | | | | + +**Notes:** + +- `#` denotes planned/WIP support +- \* Source supports legacy `JS storiesOf` and `MDX` stories. `Typescript` and new `module format` support is WIP + +## Installation + +First add the package. Make sure that the versions for your `@storybook/*` packages match: + +```sh +yarn add -D @storybook/addon-docs +``` + +The add the following line to your `.storybook/presets.js` file: + +```js +module.exports = ['@storybook/addon-docs/react/preset']; +``` + +Finally, import your stories and MDX files in `.storybook/config.js`: + +```js +import { load } from '@storybook/react'; + +// standard configuration here +// ... + +// wherever your story files are located +load(require.context('../src', true, /\.stories\.js$/), module); +load(require.context('../src', true, /\.stories\.mdx$/), module); +``` + +## Manual configuration + +Docs uses Storybook presets as a configuration shortcut. To configure "the long way", first register the addon in `.storybook/addons.js`: + +```js +import '@storybook/addon-docs/register'; +``` + +Then configure Storybook's webpack loader to understand MDX files in `.storybook/webpack.config.js`: + +```js +const createCompiler = require('@storybook/addon-docs/mdx-compiler-plugin'); + +module.exports = async ({ config }) => { + config.module.rules.push({ + test: /\.mdx$/, + use: [ + { + loader: 'babel-loader', + // may or may not need this line depending on your app's setup + plugins: ['@babel/plugin-transform-react-jsx'], + }, + { + loader: '@mdx-js/loader', + options: { + compilers: [createCompiler({})], + }, + }, + ], + }); + return config; +}; +``` diff --git a/addons/docs/__snapshots__/mdx-compiler-plugin.test.js.snap b/addons/docs/__snapshots__/mdx-compiler-plugin.test.js.snap new file mode 100644 index 000000000000..dd2d97579edb --- /dev/null +++ b/addons/docs/__snapshots__/mdx-compiler-plugin.test.js.snap @@ -0,0 +1,539 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`docs-mdx-compiler-plugin supports "smart" current story 1`] = ` +"/* @jsx mdx */ +import { DocsContainer } from '@storybook/addon-docs/blocks'; + +import { Story } from '@storybook/addon-docs/blocks'; + +const makeShortcode = name => + function MDXDefaultShortcode(props) { + console.warn( + 'Component ' + + name + + ' was not imported, exported, or provided by MDXProvider as global scope' + ); + return
; + }; + +const layoutProps = {}; +const MDXLayout = 'wrapper'; +function MDXContent({ components, ...props }) { + return ( + +

{\`Current story\`}

+ +
+ ); +} + +MDXContent.isMDXComponent = true; + +const componentMeta = {}; + +const mdxKind = componentMeta.title || componentMeta.displayName; +const WrappedMDXContent = ({ context }) => ( + +); +componentMeta.parameters = componentMeta.parameters || {}; +componentMeta.parameters.docs = WrappedMDXContent; + +export default componentMeta; +" +`; + +exports[`docs-mdx-compiler-plugin supports decorators 1`] = ` +"/* @jsx mdx */ +import { DocsContainer } from '@storybook/addon-docs/blocks'; + +import { Button } from '@storybook/react/demo'; +import { Story, Meta } from '@storybook/addon-docs/blocks'; + +const makeShortcode = name => + function MDXDefaultShortcode(props) { + console.warn( + 'Component ' + + name + + ' was not imported, exported, or provided by MDXProvider as global scope' + ); + return
; + }; + +const layoutProps = {}; +const MDXLayout = 'wrapper'; +function MDXContent({ components, ...props }) { + return ( + + ( +
+ {storyFn()} +
+ ), + ]} + mdxType=\\"Meta\\" + /> +

{\`Decorated story\`}

+ + + +
+ ); +} + +MDXContent.isMDXComponent = true; + +export const one = () => ; +one.parameters = { mdxSource: \`\` }; + +const componentMeta = { + title: 'Button', + decorators: [ + storyFn => ( +
+ {storyFn()} +
+ ), + ], +}; + +const mdxKind = componentMeta.title || componentMeta.displayName; +const WrappedMDXContent = ({ context }) => ( + +); +componentMeta.parameters = componentMeta.parameters || {}; +componentMeta.parameters.docs = WrappedMDXContent; + +export default componentMeta; +" +`; + +exports[`docs-mdx-compiler-plugin supports object-style story definitions 1`] = ` +"/* @jsx mdx */ +import { DocsContainer } from '@storybook/addon-docs/blocks'; + +import { Story, Meta } from '@storybook/addon-docs/blocks'; +import { Welcome, Button } from '@storybook/angular/demo'; +import { linkTo } from '@storybook/addon-links'; + +const makeShortcode = name => + function MDXDefaultShortcode(props) { + console.warn( + 'Component ' + + name + + ' was not imported, exported, or provided by MDXProvider as global scope' + ); + return
; + }; + +const layoutProps = {}; +const MDXLayout = 'wrapper'; +function MDXContent({ components, ...props }) { + return ( + + +

{\`Story object\`}

+ + {{ + template: \`\`, + props: { + showApp: linkTo('Button'), + }, + moduleMetadata: { + declarations: [Welcome], + }, + }} + +
+ ); +} + +MDXContent.isMDXComponent = true; + +export const toStorybook = () => ({ + template: \`\`, + props: { + showApp: linkTo('Button'), + }, + moduleMetadata: { + declarations: [Welcome], + }, +}); +toStorybook.title = 'to storybook'; +toStorybook.parameters = { + mdxSource: \`{ + template: \\\\\`\\\\\`, + props: { + showApp: linkTo('Button') + }, + moduleMetadata: { + declarations: [Welcome] + } +}\`, +}; + +const componentMeta = { title: 'MDX|Welcome' }; + +const mdxKind = componentMeta.title || componentMeta.displayName; +const WrappedMDXContent = ({ context }) => ( + +); +componentMeta.parameters = componentMeta.parameters || {}; +componentMeta.parameters.docs = WrappedMDXContent; + +export default componentMeta; +" +`; + +exports[`docs-mdx-compiler-plugin supports parameters 1`] = ` +"/* @jsx mdx */ +import { DocsContainer } from '@storybook/addon-docs/blocks'; + +import { Button } from '@storybook/react/demo'; +import { Story, Meta } from '@storybook/addon-docs/blocks'; + +const makeShortcode = name => + function MDXDefaultShortcode(props) { + console.warn( + 'Component ' + + name + + ' was not imported, exported, or provided by MDXProvider as global scope' + ); + return
; + }; + +const layoutProps = {}; +const MDXLayout = 'wrapper'; +function MDXContent({ components, ...props }) { + return ( + + + + + + + + + + ); +} + +MDXContent.isMDXComponent = true; + +export const componentNotes = () => ; +componentNotes.title = 'component notes'; +componentNotes.parameters = { mdxSource: \`\` }; + +export const storyNotes = () => ; +storyNotes.title = 'story notes'; +storyNotes.parameters = { + mdxSource: \`\`, + ...{ + notes: 'story notes', + }, +}; + +const componentMeta = { + title: 'Button', + parameters: { + component: Button, + notes: 'component notes', + }, +}; + +const mdxKind = componentMeta.title || componentMeta.displayName; +const WrappedMDXContent = ({ context }) => ( + +); +componentMeta.parameters = componentMeta.parameters || {}; +componentMeta.parameters.docs = WrappedMDXContent; + +export default componentMeta; +" +`; + +exports[`docs-mdx-compiler-plugin supports previews 1`] = ` +"/* @jsx mdx */ +import { DocsContainer } from '@storybook/addon-docs/blocks'; + +import { Button } from '@storybook/react/demo'; +import { Preview, Story, Meta } from '@storybook/addon-docs/blocks'; + +const makeShortcode = name => + function MDXDefaultShortcode(props) { + console.warn( + 'Component ' + + name + + ' was not imported, exported, or provided by MDXProvider as global scope' + ); + return
; + }; + +const layoutProps = {}; +const MDXLayout = 'wrapper'; +function MDXContent({ components, ...props }) { + return ( + + +

{\`Preview\`}

+

{\`Previews can contain normal components, stories, and story references\`}

+ + + + + + + + + + +
+ ); +} + +MDXContent.isMDXComponent = true; + +export const helloButton = () => ; +helloButton.title = 'hello button'; +helloButton.parameters = { mdxSource: \`\` }; + +export const two = () => ; +two.parameters = { mdxSource: \`\` }; + +const componentMeta = { + title: 'Button', + parameters: { + component: Button, + notes: 'component notes', + }, +}; + +const mdxKind = componentMeta.title || componentMeta.displayName; +const WrappedMDXContent = ({ context }) => ( + +); +componentMeta.parameters = componentMeta.parameters || {}; +componentMeta.parameters.docs = WrappedMDXContent; + +export default componentMeta; +" +`; + +exports[`docs-mdx-compiler-plugin supports story definitions 1`] = ` +"/* @jsx mdx */ +import { DocsContainer } from '@storybook/addon-docs/blocks'; + +import { Button } from '@storybook/react/demo'; +import { Story, Meta } from '@storybook/addon-docs/blocks'; + +const makeShortcode = name => + function MDXDefaultShortcode(props) { + console.warn( + 'Component ' + + name + + ' was not imported, exported, or provided by MDXProvider as global scope' + ); + return
; + }; + +const layoutProps = {}; +const MDXLayout = 'wrapper'; +function MDXContent({ components, ...props }) { + return ( + + +

{\`Story definition\`}

+ + + + + + +
+ ); +} + +MDXContent.isMDXComponent = true; + +export const one = () => ; +one.parameters = { mdxSource: \`\` }; + +export const helloStory = () => ; +helloStory.title = 'hello story'; +helloStory.parameters = { mdxSource: \`\` }; + +const componentMeta = { title: 'Button' }; + +const mdxKind = componentMeta.title || componentMeta.displayName; +const WrappedMDXContent = ({ context }) => ( + +); +componentMeta.parameters = componentMeta.parameters || {}; +componentMeta.parameters.docs = WrappedMDXContent; + +export default componentMeta; +" +`; + +exports[`docs-mdx-compiler-plugin supports story references 1`] = ` +"/* @jsx mdx */ +import { DocsContainer } from '@storybook/addon-docs/blocks'; + +import { Story } from '@storybook/addon-docs/blocks'; + +const makeShortcode = name => + function MDXDefaultShortcode(props) { + console.warn( + 'Component ' + + name + + ' was not imported, exported, or provided by MDXProvider as global scope' + ); + return
; + }; + +const layoutProps = {}; +const MDXLayout = 'wrapper'; +function MDXContent({ components, ...props }) { + return ( + +

{\`Story reference\`}

+ +
+ ); +} + +MDXContent.isMDXComponent = true; + +const componentMeta = {}; + +const mdxKind = componentMeta.title || componentMeta.displayName; +const WrappedMDXContent = ({ context }) => ( + +); +componentMeta.parameters = componentMeta.parameters || {}; +componentMeta.parameters.docs = WrappedMDXContent; + +export default componentMeta; +" +`; + +exports[`docs-mdx-compiler-plugin supports text-only story definitions 1`] = ` +"/* @jsx mdx */ +import { DocsContainer } from '@storybook/addon-docs/blocks'; + +import { Story, Meta } from '@storybook/addon-docs/blocks'; + +const makeShortcode = name => + function MDXDefaultShortcode(props) { + console.warn( + 'Component ' + + name + + ' was not imported, exported, or provided by MDXProvider as global scope' + ); + return
; + }; + +const layoutProps = {}; +const MDXLayout = 'wrapper'; +function MDXContent({ components, ...props }) { + return ( + + +

{\`Story definition\`}

+ + Plain text + +
+ ); +} + +MDXContent.isMDXComponent = true; + +export const text = () => 'Plain text'; +text.parameters = { mdxSource: \`'Plain text'\` }; + +const componentMeta = { title: 'Text' }; + +const mdxKind = componentMeta.title || componentMeta.displayName; +const WrappedMDXContent = ({ context }) => ( + +); +componentMeta.parameters = componentMeta.parameters || {}; +componentMeta.parameters.docs = WrappedMDXContent; + +export default componentMeta; +" +`; + +exports[`docs-mdx-compiler-plugin supports vanilla mdx 1`] = ` +"/* @jsx mdx */ +import { DocsContainer } from '@storybook/addon-docs/blocks'; + +import { Button } from '@storybook/react/demo'; + +const makeShortcode = name => + function MDXDefaultShortcode(props) { + console.warn( + 'Component ' + + name + + ' was not imported, exported, or provided by MDXProvider as global scope' + ); + return
; + }; + +const layoutProps = {}; +const MDXLayout = 'wrapper'; +function MDXContent({ components, ...props }) { + return ( + +

{\`Hello MDX\`}

+

{\`This is some random content.\`}

+ +
+ ); +} + +MDXContent.isMDXComponent = true; + +const componentMeta = {}; + +const mdxKind = componentMeta.title || componentMeta.displayName; +const WrappedMDXContent = ({ context }) => ( + +); +componentMeta.parameters = componentMeta.parameters || {}; +componentMeta.parameters.docs = WrappedMDXContent; + +export default componentMeta; +" +`; diff --git a/addons/docs/common/index.js b/addons/docs/common/index.js new file mode 100644 index 000000000000..ab2313695b6d --- /dev/null +++ b/addons/docs/common/index.js @@ -0,0 +1,2 @@ +// FIXME: move this to typescript and src/react folder +module.exports = require('../dist/lib/getPropDefs'); diff --git a/addons/docs/common/preset.js b/addons/docs/common/preset.js new file mode 100644 index 000000000000..da25537f1083 --- /dev/null +++ b/addons/docs/common/preset.js @@ -0,0 +1,82 @@ +const createCompiler = require('../mdx-compiler-plugin'); + +function createBabelOptions({ babelOptions, configureJSX }) { + if (!configureJSX) { + return babelOptions; + } + + return { + ...babelOptions, + // for frameworks that are not working with react, we need to configure + // the jsx to transpile mdx, for now there will be a flag for that + // for more complex solutions we can find alone that we need to add '@babel/plugin-transform-react-jsx' + plugins: [...babelOptions.plugins, '@babel/plugin-transform-react-jsx'], + }; +} + +function webpack(webpackConfig = {}, options = {}) { + const { module = {} } = webpackConfig; + // it will reuse babel options that are already in use in storybook + // also, these babel options are chained with other presets. + const { babelOptions, configureJSX } = options; + + return { + ...webpackConfig, + module: { + ...module, + rules: [ + ...(module.rules || []), + // { + // test: [/\.stories\.(jsx?$|ts?$)/], + // enforce: 'pre', + // use: [ + // { + // loader: require.resolve('@storybook/addon-storysource/loader'), + // options: { + // injectParameters: true, + // }, + // }, + // ], + // }, + { + test: /\.stories.mdx$/, + use: [ + { + loader: 'babel-loader', + options: createBabelOptions({ babelOptions, configureJSX }), + }, + { + loader: '@mdx-js/loader', + options: { + compilers: [createCompiler(options)], + }, + }, + ], + }, + { + test: /\.mdx$/, + exclude: /\.stories.mdx$/, + use: [ + { + loader: 'babel-loader', + options: createBabelOptions({ babelOptions, configureJSX }), + }, + { + loader: '@mdx-js/loader', + }, + ], + }, + ], + }, + }; +} + +function addons(entry = []) { + return [ + ...entry, + // require.resolve('@storybook/addon-storysource/register'), + require.resolve('../register'), + ]; +} + +module.exports = { webpack, addons }; diff --git a/addons/docs/fixtures/decorators.mdx b/addons/docs/fixtures/decorators.mdx new file mode 100644 index 000000000000..2f4e84e6ded0 --- /dev/null +++ b/addons/docs/fixtures/decorators.mdx @@ -0,0 +1,13 @@ +import { Button } from '@storybook/react/demo'; +import { Story, Meta } from '@storybook/addon-docs/blocks'; + +
{storyFn()}
]} +/> + +# Decorated story + + + + diff --git a/addons/docs/fixtures/parameters.mdx b/addons/docs/fixtures/parameters.mdx new file mode 100644 index 000000000000..0805466b38cd --- /dev/null +++ b/addons/docs/fixtures/parameters.mdx @@ -0,0 +1,12 @@ +import { Button } from '@storybook/react/demo'; +import { Story, Meta } from '@storybook/addon-docs/blocks'; + + + + + + + + + + diff --git a/addons/docs/fixtures/previews.mdx b/addons/docs/fixtures/previews.mdx new file mode 100644 index 000000000000..80601eed2ed0 --- /dev/null +++ b/addons/docs/fixtures/previews.mdx @@ -0,0 +1,19 @@ +import { Button } from '@storybook/react/demo'; +import { Preview, Story, Meta } from '@storybook/addon-docs/blocks'; + + + +# Preview + +Previews can contain normal components, stories, and story references + + + + + + + + + + + diff --git a/addons/docs/fixtures/story-current.mdx b/addons/docs/fixtures/story-current.mdx new file mode 100644 index 000000000000..d5b62cc6edab --- /dev/null +++ b/addons/docs/fixtures/story-current.mdx @@ -0,0 +1,5 @@ +import { Story } from '@storybook/addon-docs/blocks'; + +# Current story + + diff --git a/addons/docs/fixtures/story-def-text-only.mdx b/addons/docs/fixtures/story-def-text-only.mdx new file mode 100644 index 000000000000..78ebd50215ee --- /dev/null +++ b/addons/docs/fixtures/story-def-text-only.mdx @@ -0,0 +1,7 @@ +import { Story, Meta } from '@storybook/addon-docs/blocks'; + + + +# Story definition + +Plain text diff --git a/addons/docs/fixtures/story-definitions.mdx b/addons/docs/fixtures/story-definitions.mdx new file mode 100644 index 000000000000..ee5c355b9892 --- /dev/null +++ b/addons/docs/fixtures/story-definitions.mdx @@ -0,0 +1,14 @@ +import { Button } from '@storybook/react/demo'; +import { Story, Meta } from '@storybook/addon-docs/blocks'; + + + +# Story definition + + + + + + + + diff --git a/addons/docs/fixtures/story-missing-props.mdx b/addons/docs/fixtures/story-missing-props.mdx new file mode 100644 index 000000000000..0eb3137a9756 --- /dev/null +++ b/addons/docs/fixtures/story-missing-props.mdx @@ -0,0 +1,10 @@ +import { Button } from '@storybook/react/demo'; +import { Story, Meta } from '@storybook/addon-docs/blocks'; + + + +# Bad story + + + + diff --git a/addons/docs/fixtures/story-object.mdx b/addons/docs/fixtures/story-object.mdx new file mode 100644 index 000000000000..e63d48923842 --- /dev/null +++ b/addons/docs/fixtures/story-object.mdx @@ -0,0 +1,19 @@ +import { Story, Meta } from '@storybook/addon-docs/blocks'; +import { Welcome, Button } from '@storybook/angular/demo'; +import { linkTo } from '@storybook/addon-links'; + + + +# Story object + + + {{ + template: ``, + props: { + showApp: linkTo('Button'), + }, + moduleMetadata: { + declarations: [Welcome], + }, + }} + diff --git a/addons/docs/fixtures/story-references.mdx b/addons/docs/fixtures/story-references.mdx new file mode 100644 index 000000000000..865bd5dea49b --- /dev/null +++ b/addons/docs/fixtures/story-references.mdx @@ -0,0 +1,5 @@ +import { Story } from '@storybook/addon-docs/blocks'; + +# Story reference + + diff --git a/addons/docs/fixtures/vanilla.mdx b/addons/docs/fixtures/vanilla.mdx new file mode 100644 index 000000000000..93ccac3d6bc3 --- /dev/null +++ b/addons/docs/fixtures/vanilla.mdx @@ -0,0 +1,7 @@ +import { Button } from '@storybook/react/demo'; + +# Hello MDX + +This is some random content. + + diff --git a/addons/docs/mdx-compiler-plugin.js b/addons/docs/mdx-compiler-plugin.js new file mode 100644 index 000000000000..304b3f86e94a --- /dev/null +++ b/addons/docs/mdx-compiler-plugin.js @@ -0,0 +1,201 @@ +const mdxToJsx = require('@mdx-js/mdx/mdx-hast-to-jsx'); +const parser = require('@babel/parser'); +const generate = require('@babel/generator').default; +const camelCase = require('lodash/camelCase'); + +// Generate the MDX as is, but append named exports for every +// story in the contents + +const STORY_REGEX = /^]/; +const PREVIEW_REGEX = /^]/; +const META_REGEX = /^]/; +const RESERVED = /^(?:do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|await|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$/; + +function getAttr(elt, what) { + const attr = elt.attributes.find(n => n.name.name === what); + return attr && attr.value; +} + +function getStoryFn(name, counter) { + if (name) { + const storyFn = camelCase(name.replace(/[^a-z0-9-]/g, '-')); + if (storyFn.length > 1 && !RESERVED.exec(storyFn)) { + return storyFn; + } + } + return `story${counter}`; +} + +function genStoryExport(ast, counter) { + let storyName = getAttr(ast.openingElement, 'name'); + let storyId = getAttr(ast.openingElement, 'id'); + storyName = storyName && storyName.value; + storyId = storyId && storyId.value; + + if (!storyId && !storyName) { + throw new Error('Expected a story name or ID attribute'); + } + + // We don't generate exports for story references or the smart "current story" + if (storyId || !storyName) { + return null; + } + + // console.log('genStoryExport', JSON.stringify(ast, null, 2)); + + const statements = []; + const storyFn = getStoryFn(storyName, counter); + + let body = ast.children.find(n => n.type !== 'JSXText'); + let storyCode = null; + if (!body) { + // plain text node + const { code } = generate(ast.children[0], {}); + storyCode = `'${code}'`; + } else { + if (body.type === 'JSXExpressionContainer') { + // FIXME: handle fragments + body = body.expression; + } + const { code } = generate(body, {}); + storyCode = code; + } + statements.push( + `export const ${storyFn} = () => ( + ${storyCode} + );` + ); + + if (storyName !== storyFn) { + statements.push(`${storyFn}.title = '${storyName}';`); + } + + let parameters = getAttr(ast.openingElement, 'parameters'); + parameters = parameters && parameters.expression; + const source = `\`${storyCode.replace(/`/g, '\\`')}\``; + if (parameters) { + const { code: params } = generate(parameters, {}); + // FIXME: hack in the story's source as a parameter + statements.push(`${storyFn}.parameters = { mdxSource: ${source}, ...${params} };`); + } else { + statements.push(`${storyFn}.parameters = { mdxSource: ${source} };`); + } + + // console.log(statements); + + return [statements.join('\n')]; +} + +function genPreviewExports(ast, counter) { + // console.log('genPreviewExports', JSON.stringify(ast, null, 2)); + + let localCounter = counter; + const previewExports = []; + for (let i = 0; i < ast.children.length; i += 1) { + const child = ast.children[i]; + if (child.type === 'JSXElement' && child.openingElement.name.name === 'Story') { + const storyExport = genStoryExport(child, localCounter); + if (storyExport) { + previewExports.push(storyExport); + localCounter += 1; + } + } + } + return previewExports; +} + +function genMetaExport(ast) { + let title = getAttr(ast.openingElement, 'title'); + let parameters = getAttr(ast.openingElement, 'parameters'); + let decorators = getAttr(ast.openingElement, 'decorators'); + title = title && `title: '${title.value}',`; + if (parameters && parameters.expression) { + const { code: params } = generate(parameters.expression, {}); + parameters = `parameters: ${params},`; + } + if (decorators && decorators.expression) { + const { code: decos } = generate(decorators.expression, {}); + decorators = `decorators: ${decos},`; + } + return `const componentMeta = { ${title || ''} ${parameters || ''} ${decorators || ''} };`; +} + +function getExports(node, counter) { + const { value, type } = node; + if (type === 'jsx') { + if (STORY_REGEX.exec(value)) { + // Single story + const ast = parser.parseExpression(value, { plugins: ['jsx'] }); + const storyExport = genStoryExport(ast, counter); + return storyExport && { stories: [storyExport] }; + } + if (PREVIEW_REGEX.exec(value)) { + // Preview, possibly containing multiple stories + const ast = parser.parseExpression(value, { plugins: ['jsx'] }); + return { stories: genPreviewExports(ast, counter) }; + } + if (META_REGEX.exec(value)) { + // Preview, possibly containing multiple stories + const ast = parser.parseExpression(value, { plugins: ['jsx'] }); + return { meta: genMetaExport(ast) }; + } + } + return null; +} + +// insert `mdxKind` into the context so that we can know what "kind" we're rendering into +// when we render ..., since this MDX can be attached to any `selectedKind`! +const wrapperJs = ` +const mdxKind = componentMeta.title || componentMeta.displayName; +const WrappedMDXContent = ({ context }) => ; +componentMeta.parameters = componentMeta.parameters || {}; +componentMeta.parameters.docs = WrappedMDXContent; +`.trim(); + +function extractExports(node, options) { + // we're overriding default export + const defaultJsx = mdxToJsx.toJSX(node, {}, { ...options, skipExport: true }); + const storyExports = []; + let metaExport = null; + let counter = 0; + node.children.forEach(n => { + const exports = getExports(n, counter); + if (exports) { + const { stories, meta } = exports; + if (stories) { + stories.forEach(story => { + storyExports.push(story); + counter += 1; + }); + } + if (meta) { + if (metaExport) { + throw new Error('Meta can only be declared once'); + } + metaExport = meta; + } + } + }); + if (!metaExport) { + metaExport = 'const componentMeta = { };'; + } + + const fullJsx = [ + 'import { DocsContainer } from "@storybook/addon-docs/blocks";', + defaultJsx, + ...storyExports, + metaExport, + wrapperJs, + 'export default componentMeta;', + ].join('\n\n'); + + return fullJsx; +} + +function createCompiler(mdxOptions) { + return function compiler(options = {}) { + this.Compiler = tree => extractExports(tree, options, mdxOptions); + }; +} + +module.exports = createCompiler; diff --git a/addons/docs/mdx-compiler-plugin.test.js b/addons/docs/mdx-compiler-plugin.test.js new file mode 100644 index 000000000000..fd24254f15ae --- /dev/null +++ b/addons/docs/mdx-compiler-plugin.test.js @@ -0,0 +1,71 @@ +const path = require('path'); +const fs = require('fs-extra'); +const mdx = require('@mdx-js/mdx'); +const prettier = require('prettier'); +const plugin = require('./mdx-compiler-plugin'); + +function format(code) { + return prettier.format(code, { + parser: 'babel', + printWidth: 100, + tabWidth: 2, + bracketSpacing: true, + trailingComma: 'es5', + singleQuote: true, + }); +} + +async function generate(filePath) { + const content = await fs.readFile(filePath, 'utf8'); + + const result = mdx.sync(content, { + filepath: filePath, + compilers: [plugin({})], + }); + + return format(result); +} + +describe('docs-mdx-compiler-plugin', () => { + it('supports vanilla mdx', async () => { + const code = await generate(path.resolve(__dirname, './fixtures/vanilla.mdx')); + expect(code).toMatchSnapshot(); + }); + it('supports story definitions', async () => { + const code = await generate(path.resolve(__dirname, './fixtures/story-definitions.mdx')); + expect(code).toMatchSnapshot(); + }); + it('supports text-only story definitions', async () => { + const code = await generate(path.resolve(__dirname, './fixtures/story-def-text-only.mdx')); + expect(code).toMatchSnapshot(); + }); + it('supports object-style story definitions', async () => { + const code = await generate(path.resolve(__dirname, './fixtures/story-object.mdx')); + expect(code).toMatchSnapshot(); + }); + it('supports story references', async () => { + const code = await generate(path.resolve(__dirname, './fixtures/story-references.mdx')); + expect(code).toMatchSnapshot(); + }); + it('supports "smart" current story', async () => { + const code = await generate(path.resolve(__dirname, './fixtures/story-current.mdx')); + expect(code).toMatchSnapshot(); + }); + it('supports previews', async () => { + const code = await generate(path.resolve(__dirname, './fixtures/previews.mdx')); + expect(code).toMatchSnapshot(); + }); + it('supports decorators', async () => { + const code = await generate(path.resolve(__dirname, './fixtures/decorators.mdx')); + expect(code).toMatchSnapshot(); + }); + it('supports parameters', async () => { + const code = await generate(path.resolve(__dirname, './fixtures/parameters.mdx')); + expect(code).toMatchSnapshot(); + }); + it('errors on missing story props', async () => { + await expect( + generate(path.resolve(__dirname, './fixtures/story-missing-props.mdx')) + ).rejects.toThrow('Expected a story name or ID attribute'); + }); +}); diff --git a/addons/docs/package.json b/addons/docs/package.json index ec56c61947fd..a900f076f2d5 100644 --- a/addons/docs/package.json +++ b/addons/docs/package.json @@ -23,6 +23,11 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.2", + "@mdx-js/loader": "^1.0.0", + "@mdx-js/mdx": "^1.0.0", + "@mdx-js/react": "^1.0.16", "@storybook/addons": "5.2.0-alpha.23", "@storybook/api": "5.2.0-alpha.23", "@storybook/components": "5.2.0-alpha.23", @@ -30,6 +35,7 @@ "@storybook/theming": "5.2.0-alpha.23", "core-js": "^3.0.1", "global": "^4.3.2", + "lodash": "^4.17.11", "prop-types": "^15.7.2" }, "devDependencies": { diff --git a/addons/docs/react/index.js b/addons/docs/react/index.js new file mode 100644 index 000000000000..38c1756201b7 --- /dev/null +++ b/addons/docs/react/index.js @@ -0,0 +1 @@ +module.exports = require('../common/index'); diff --git a/addons/docs/react/preset.js b/addons/docs/react/preset.js new file mode 100644 index 000000000000..a9b8af2cce0a --- /dev/null +++ b/addons/docs/react/preset.js @@ -0,0 +1 @@ +module.exports = require('../common/preset'); diff --git a/addons/docs/src/blocks/DocsContainer.tsx b/addons/docs/src/blocks/DocsContainer.tsx index a94443b3503f..1e829cbbfbd4 100644 --- a/addons/docs/src/blocks/DocsContainer.tsx +++ b/addons/docs/src/blocks/DocsContainer.tsx @@ -1,7 +1,7 @@ /* eslint-disable react/destructuring-assignment */ import React from 'react'; -// import { MDXProvider } from '@mdx-js/react'; +import { MDXProvider } from '@mdx-js/react'; import { Global, createGlobal, ThemeProvider, ensure as ensureTheme } from '@storybook/theming'; import { DocumentFormatting, DocsWrapper, DocsContent } from '@storybook/components'; import { DocsContextProps, DocsContext } from './DocsContext'; @@ -39,13 +39,13 @@ export const DocsContainer: React.FunctionComponent = ({ - {/* */} - - - - - - {/* */} + + + + + + + ); diff --git a/addons/docs/src/typings.d.ts b/addons/docs/src/typings.d.ts new file mode 100644 index 000000000000..005ee92d6b8f --- /dev/null +++ b/addons/docs/src/typings.d.ts @@ -0,0 +1 @@ +declare module '@mdx-js/react'; diff --git a/addons/docs/vue/index.js b/addons/docs/vue/index.js new file mode 100644 index 000000000000..38c1756201b7 --- /dev/null +++ b/addons/docs/vue/index.js @@ -0,0 +1 @@ +module.exports = require('../common/index'); diff --git a/addons/docs/vue/preset.js b/addons/docs/vue/preset.js new file mode 100644 index 000000000000..a9b8af2cce0a --- /dev/null +++ b/addons/docs/vue/preset.js @@ -0,0 +1 @@ +module.exports = require('../common/preset'); diff --git a/examples/official-storybook/config.js b/examples/official-storybook/config.js index c9fd2c34292d..ae4db10692d7 100644 --- a/examples/official-storybook/config.js +++ b/examples/official-storybook/config.js @@ -63,3 +63,4 @@ addParameters({ load(require.context('../../lib/ui/src', true, /\.stories\.js$/), module); load(require.context('../../lib/components/src', true, /\.stories\.tsx?$/), module); load(require.context('./stories', true, /\.stories\.js$/), module); +load(require.context('./stories', true, /\.stories\.mdx$/), module); diff --git a/examples/official-storybook/presets.js b/examples/official-storybook/presets.js new file mode 100644 index 000000000000..b1d463490f6d --- /dev/null +++ b/examples/official-storybook/presets.js @@ -0,0 +1 @@ +module.exports = ['@storybook/addon-docs/react/preset']; diff --git a/examples/official-storybook/stories/addon-docs.stories.js b/examples/official-storybook/stories/addon-docs.stories.js index 5571d08c30cd..533f7adbe662 100644 --- a/examples/official-storybook/stories/addon-docs.stories.js +++ b/examples/official-storybook/stories/addon-docs.stories.js @@ -1,8 +1,37 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; +import notes from './notes/notes.md'; +import mdxNotes from './notes/notes.mdx'; +import DocgenButton from '../components/DocgenButton'; -storiesOf('Addons|Docs', module) - .addParameters({ - docs: () =>
Hello docs
, - }) - .add('default', () =>
Click the docs tab to see the docs
); +export default { + title: 'Addons|Docs/stories', + parameters: { + component: DocgenButton, + }, +}; + +export const basic = () =>
Click docs tab to see basic docs
; + +export const withNotes = () =>
Click docs tab to see DocsPage docs
; +withNotes.title = 'with notes'; +withNotes.parameters = { + notes, +}; + +export const withInfo = () =>
Click docs tab to see DocsPage docs
; +withInfo.title = 'with info'; +withInfo.parameters = { + info: 'some user info string', +}; + +export const mdxOverride = () =>
Click docs tab to see MDX-overridden docs
; +mdxOverride.title = 'mdx override'; +mdxOverride.parameters = { + docs: mdxNotes, +}; + +export const jsxOverride = () =>
Click docs tab to see JSX-overridden docs
; +jsxOverride.title = 'jsx override'; +jsxOverride.parameters = { + docs: () =>
Hello docs
, +}; diff --git a/examples/official-storybook/stories/addon-docs.stories.mdx b/examples/official-storybook/stories/addon-docs.stories.mdx new file mode 100644 index 000000000000..dad4ac526597 --- /dev/null +++ b/examples/official-storybook/stories/addon-docs.stories.mdx @@ -0,0 +1,80 @@ +import { + Story, + Preview, + Props, + Source, + Description, + ColorPalette, + ColorItem, + Meta, +} from '@storybook/addon-docs/blocks'; +import { action } from '@storybook/addon-actions'; +import { Button } from '@storybook/react/demo'; + +
{storyFn()}
]} + parameters={{ component: Button, notes: 'component notes' }} +/> + +# Selected + + + + + + + +## A random color ColorPalette + + + + + + + + +## Getting into details + + + + + + + + + + + + + + + + + Plain text + + + + +## Configurable height + + + +## Description + + + + diff --git a/examples/official-storybook/stories/notes/notes.mdx b/examples/official-storybook/stories/notes/notes.mdx new file mode 100644 index 000000000000..48dc5de86eae --- /dev/null +++ b/examples/official-storybook/stories/notes/notes.mdx @@ -0,0 +1,3 @@ +# Welcome! + +Let's just write markdown without stories diff --git a/lib/core/src/client/preview/start.js b/lib/core/src/client/preview/start.js index 6dc6fd7bc8a3..77a84389d1bf 100644 --- a/lib/core/src/client/preview/start.js +++ b/lib/core/src/client/preview/start.js @@ -162,7 +162,13 @@ export default function start(render, { decorateStory } = {}) { kind === previousKind && name === previousStory ) { - addons.getChannel().emit(Events.STORY_UNCHANGED, id); + addons.getChannel().emit(Events.STORY_UNCHANGED, { + id, + revision, + kind, + name, + viewMode, + }); return; } @@ -271,7 +277,9 @@ export default function start(render, { decorateStory } = {}) { if (!fileExports.default.title) { throw new Error( - `Unexpected default export without title: ${JSON.stringify(fileExports.default)}` + `Unexpected default export without title in '${filename}': ${JSON.stringify( + fileExports.default + )}` ); } diff --git a/yarn.lock b/yarn.lock index cb304d8a382f..446f6c3d332a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -539,7 +539,7 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.1.6", "@babel/parser@^7.4.3", "@babel/parser@^7.4.4", "@babel/parser@^7.4.5": +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.1.6", "@babel/parser@^7.4.2", "@babel/parser@^7.4.3", "@babel/parser@^7.4.4", "@babel/parser@^7.4.5": version "7.4.5" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.5.tgz#04af8d5d5a2b044a2a1bffacc1e5e6673544e872" integrity sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew== @@ -3144,6 +3144,41 @@ npmlog "^4.1.2" write-file-atomic "^2.3.0" +"@mdx-js/loader@^1.0.0": + version "1.0.21" + resolved "https://registry.yarnpkg.com/@mdx-js/loader/-/loader-1.0.21.tgz#72fa5422ead35ac68aa452a032a84dd4f49e845b" + integrity sha512-1e/OZSGRSJHjp/ICroPVgja3v97q4pKm1TTFo/Hn1G5DWihOIFf+PUZgqD58Y1mbWhSHZrP4ZLmySVjmCjgUog== + dependencies: + "@mdx-js/mdx" "^1.0.21" + "@mdx-js/react" "^1.0.21" + loader-utils "^1.1.0" + +"@mdx-js/mdx@^1.0.0", "@mdx-js/mdx@^1.0.21": + version "1.0.21" + resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-1.0.21.tgz#028a7975fff026222f7ace19c8c130290c649025" + integrity sha512-B+n3PvrtdUcaCgDmWFaBf4n/zsls5hoyNPkWe2CzUx3ggR0SoD4UqCQR7iIZZ//fUjAwFODGf+2H0aJ3tIlB7w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.2.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + change-case "^3.0.2" + detab "^2.0.0" + hast-util-raw "^5.0.0" + lodash.uniq "^4.5.0" + mdast-util-to-hast "^4.0.0" + remark-mdx "^1.0.21" + remark-parse "^6.0.0" + remark-squeeze-paragraphs "^3.0.1" + to-style "^1.3.3" + unified "^7.0.0" + unist-builder "^1.0.1" + unist-util-visit "^1.3.0" + +"@mdx-js/react@^1.0.16", "@mdx-js/react@^1.0.21": + version "1.0.21" + resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-1.0.21.tgz#fc569b86d19f426774591fa401d999ddf6ea5948" + integrity sha512-+7H1UfIytxKN/nSdojCRzUM/ZeQ6/EUg8F9bnY2NnPGuF+67cug6vZBAx9famtAey0Ms0dr2QAuCOd8k3SkhJg== + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -7645,7 +7680,7 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camel-case@3.0.x: +camel-case@3.0.x, camel-case@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= @@ -7807,6 +7842,30 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" +change-case@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/change-case/-/change-case-3.1.0.tgz#0e611b7edc9952df2e8513b27b42de72647dd17e" + integrity sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw== + dependencies: + camel-case "^3.0.0" + constant-case "^2.0.0" + dot-case "^2.1.0" + header-case "^1.0.0" + is-lower-case "^1.1.0" + is-upper-case "^1.1.0" + lower-case "^1.1.1" + lower-case-first "^1.0.0" + no-case "^2.3.2" + param-case "^2.1.0" + pascal-case "^2.0.0" + path-case "^2.1.0" + sentence-case "^2.1.0" + snake-case "^2.1.0" + swap-case "^1.1.0" + title-case "^2.1.0" + upper-case "^1.1.1" + upper-case-first "^1.1.0" + change-emitter@^0.1.2: version "0.1.6" resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515" @@ -8230,7 +8289,7 @@ codemirror@^5.26.0: resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.47.0.tgz#c13a521ae5660d3acc655af252f4955065293789" integrity sha512-kV49Fr+NGFHFc/Imsx6g180hSlkGhuHxTSDDmDHOuyln0MQYFLixDY4+bFkBVeCEiepYfDimAF/e++9jPJk4QA== -collapse-white-space@^1.0.2, collapse-white-space@^1.0.4: +collapse-white-space@^1.0.0, collapse-white-space@^1.0.2, collapse-white-space@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.5.tgz#c2495b699ab1ed380d29a1091e01063e75dbbe3a" integrity sha512-703bOOmytCYAX9cXYqoikYIx6twmFCXsnzRQheBcTG3nzKYBR4P/+wkYeH+Mvj7qUz8zZDtdyzbxfnEi/kYzRQ== @@ -8580,6 +8639,14 @@ consolidate@^0.15.1: dependencies: bluebird "^3.1.1" +constant-case@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-2.0.0.tgz#4175764d389d3fa9c8ecd29186ed6005243b6a46" + integrity sha1-QXV2TTidP6nI7NKRhu1gBSQ7akY= + dependencies: + snake-case "^2.1.0" + upper-case "^1.1.1" + constants-browserify@^1.0.0, constants-browserify@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" @@ -9233,7 +9300,7 @@ css-what@2.1, css-what@^2.1.2: resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== -css@^2.2.1: +css@2.2.4, css@^2.2.1: version "2.2.4" resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== @@ -9802,6 +9869,13 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +detab@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/detab/-/detab-2.0.2.tgz#074970d1a807b045d0258a4235df5928dd683561" + integrity sha512-Q57yPrxScy816TTE1P/uLRXLDKjXhvYTbfxS/e6lPD+YrqghbsMlGB9nQzj/zVtSPaF0DFPSdO916EWO4sQUyQ== + dependencies: + repeat-string "^1.5.4" + detect-file@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" @@ -10064,6 +10138,13 @@ domutils@^1.5.1, domutils@^1.7.0: dom-serializer "0" domelementtype "1" +dot-case@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-2.1.1.tgz#34dcf37f50a8e93c2b3bca8bb7fb9155c7da3bee" + integrity sha1-NNzzf1Co6TwrO8qLt/uRVcfaO+4= + dependencies: + no-case "^2.2.0" + dot-prop@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" @@ -13773,6 +13854,18 @@ hashids@1.1.4: resolved "https://registry.yarnpkg.com/hashids/-/hashids-1.1.4.tgz#e4ff92ad66b684a3bd6aace7c17d66618ee5fa21" integrity sha512-U/fnTE3edW0AV92ZI/BfEluMZuVcu3MDOopsN7jS+HqDYcarQo8rXQiWlsBlm0uX48/taYSdxRsfzh2HRg5Z6w== +hast-to-hyperscript@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-7.0.2.tgz#e9237c88c6069999ad38aec847fefc296f484c4c" + integrity sha512-NBMMst0hkDR21uSH75m9W2DkljBrLoMQEhGiLMLNij4HIzEDJMC1UG+CFR6EAjHi2zs3NHBoaAHJOHxftoIN2g== + dependencies: + comma-separated-tokens "^1.0.0" + property-information "^5.0.0" + space-separated-tokens "^1.0.0" + style-to-object "^0.2.1" + unist-util-is "^3.0.0" + web-namespaces "^1.1.2" + hast-util-from-parse5@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-5.0.0.tgz#a505a05766e0f96e389bfb0b1dd809eeefcef47b" @@ -13789,6 +13882,31 @@ hast-util-parse-selector@^2.2.0: resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.1.tgz#4ddbae1ae12c124e3eb91b581d2556441766f0ab" integrity sha512-Xyh0v+nHmQvrOqop2Jqd8gOdyQtE8sIP9IQf7mlVDqp924W4w/8Liuguk2L2qei9hARnQSG2m+wAOCxM7npJVw== +hast-util-raw@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/hast-util-raw/-/hast-util-raw-5.0.1.tgz#b39539cf4b9f7ccdc131f72a583502a7911b99ee" + integrity sha512-iHo7G6BjRc/GU1Yun5CIEXjil0wVnIbz11C6k0JdDichSDMtYi2+NNtk6YN7EOP0JfPstX30d3pRLfaJv5CkdA== + dependencies: + hast-util-from-parse5 "^5.0.0" + hast-util-to-parse5 "^5.0.0" + html-void-elements "^1.0.1" + parse5 "^5.0.0" + unist-util-position "^3.0.0" + web-namespaces "^1.0.0" + xtend "^4.0.1" + zwitch "^1.0.0" + +hast-util-to-parse5@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-5.1.1.tgz#cabf2dbe9ed988a5128fc708457b37cdf535a2e8" + integrity sha512-ivCeAd5FCXr7bapJIVsWMnx/EmbjkkW2TU2hd1prq+jGwiaUoK+FcpjyPNwsC5ogzCwWO669tOqIovGeLc/ntg== + dependencies: + hast-to-hyperscript "^7.0.0" + property-information "^5.0.0" + web-namespaces "^1.0.0" + xtend "^4.0.1" + zwitch "^1.0.0" + hastscript@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-5.0.0.tgz#fee10382c1bc4ba3f1be311521d368c047d2c43a" @@ -13804,6 +13922,14 @@ he@1.2.x, he@^1.1.0, he@^1.1.1: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +header-case@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/header-case/-/header-case-1.0.1.tgz#9535973197c144b09613cd65d317ef19963bd02d" + integrity sha1-lTWXMZfBRLCWE81l0xfvGZY70C0= + dependencies: + no-case "^2.2.0" + upper-case "^1.1.3" + heimdalljs-fs-monitor@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.2.2.tgz#a76d98f52dbf3aa1b7c20cebb0132e2f5eeb9204" @@ -13976,6 +14102,11 @@ html-tags@^2.0.0: resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b" integrity sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos= +html-void-elements@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-1.0.4.tgz#95e8bb5ecd6b88766569c2645f2b5f1591db9ba5" + integrity sha512-yMk3naGPLrfvUV9TdDbuYXngh/TpHbA6TrOw3HL9kS8yhwx7i309BReNg7CbAJXGE+UMJ6je5OqJ7lC63o6YuQ== + html-webpack-plugin@4.0.0-alpha.2: version "4.0.0-alpha.2" resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.0.0-alpha.2.tgz#7745967e389a57a098e26963f328ebe4c19b598d" @@ -14655,7 +14786,7 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-alphabetical@^1.0.0: +is-alphabetical@^1.0.0, is-alphabetical@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.3.tgz#eb04cc47219a8895d8450ace4715abff2258a1f8" integrity sha512-eEMa6MKpHFzw38eKm56iNNi6GJ7lf6aLLio7Kr23sJPAECscgRtZvOBYybejWDQ2bM949Y++61PY+udzj5QMLA== @@ -14905,6 +15036,13 @@ is-installed-globally@^0.1.0: global-dirs "^0.1.0" is-path-inside "^1.0.0" +is-lower-case@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-lower-case/-/is-lower-case-1.1.3.tgz#7e147be4768dc466db3bfb21cc60b31e6ad69393" + integrity sha1-fhR75HaNxGbbO/shzGCzHmrWk5M= + dependencies: + lower-case "^1.1.0" + is-npm@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-3.0.0.tgz#ec9147bfb629c43f494cf67936a961edec7e8053" @@ -15136,6 +15274,13 @@ is-unc-path@^0.1.1: dependencies: unc-path-regex "^0.1.0" +is-upper-case@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-upper-case/-/is-upper-case-1.1.2.tgz#8d0b1fa7e7933a1e58483600ec7d9661cbaf756f" + integrity sha1-jQsfp+eTOh5YSDYA7H2WYcuvdW8= + dependencies: + upper-case "^1.1.0" + is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" @@ -17616,7 +17761,14 @@ loud-rejection@^1.0.0: currently-unhandled "^0.4.1" signal-exit "^3.0.0" -lower-case@^1.1.1: +lower-case-first@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-1.0.2.tgz#e5da7c26f29a7073be02d52bac9980e5922adfa1" + integrity sha1-5dp8JvKacHO+AtUrrJmA5ZIq36E= + dependencies: + lower-case "^1.1.2" + +lower-case@^1.1.0, lower-case@^1.1.1, lower-case@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= @@ -17970,6 +18122,13 @@ mdast-comment-marker@^1.0.0: resolved "https://registry.yarnpkg.com/mdast-comment-marker/-/mdast-comment-marker-1.1.1.tgz#9c9c18e1ed57feafc1965d92b028f37c3c8da70d" integrity sha512-TWZDaUtPLwKX1pzDIY48MkSUQRDwX/HqbTB4m3iYdL/zosi/Z6Xqfdv0C0hNVKvzrPjZENrpWDt4p4odeVO0Iw== +mdast-squeeze-paragraphs@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-3.0.5.tgz#f428b6b944f8faef454db9b58f170c4183cb2e61" + integrity sha512-xX6Vbe348Y/rukQlG4W3xH+7v4ZlzUbSY4HUIQCuYrF2DrkcHx584mCaFxkWoDZKNUfyLZItHC9VAqX3kIP7XA== + dependencies: + unist-util-remove "^1.0.0" + mdast-util-compact@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-1.0.3.tgz#98a25cc8a7865761a41477b3a87d1dcef0b1e79d" @@ -17977,11 +18136,35 @@ mdast-util-compact@^1.0.0: dependencies: unist-util-visit "^1.1.0" +mdast-util-definitions@^1.2.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-1.2.4.tgz#2b54ad4eecaff9d9fcb6bf6f9f6b68b232d77ca7" + integrity sha512-HfUArPog1j4Z78Xlzy9Q4aHLnrF/7fb57cooTHypyGoe2XFNbcx/kWZDoOz+ra8CkUzvg3+VHV434yqEd1DRmA== + dependencies: + unist-util-visit "^1.0.0" + mdast-util-heading-style@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/mdast-util-heading-style/-/mdast-util-heading-style-1.0.5.tgz#81b2e60d76754198687db0e8f044e42376db0426" integrity sha512-8zQkb3IUwiwOdUw6jIhnwM6DPyib+mgzQuHAe7j2Hy1rIarU4VUxe472bp9oktqULW3xqZE+Kz6OD4Gi7IA3vw== +mdast-util-to-hast@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-4.0.0.tgz#d8467ce28ea73b4648667bc389aa39dfa9f67f18" + integrity sha512-yOTZSxR1aPvWRUxVeLaLZ1sCYrK87x2Wusp1bDM/Ao2jETBhYUKITI3nHvgy+HkZW54HuCAhHnS0mTcbECD5Ig== + dependencies: + collapse-white-space "^1.0.0" + detab "^2.0.0" + mdast-util-definitions "^1.2.0" + mdurl "^1.0.1" + trim "0.0.1" + trim-lines "^1.0.0" + unist-builder "^1.0.1" + unist-util-generated "^1.1.0" + unist-util-position "^3.0.0" + unist-util-visit "^1.1.0" + xtend "^4.0.1" + mdast-util-to-string@^1.0.2: version "1.0.6" resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.0.6.tgz#7d85421021343b33de1552fc71cb8e5b4ae7536d" @@ -19066,7 +19249,7 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -no-case@^2.2.0: +no-case@^2.2.0, no-case@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== @@ -20132,7 +20315,7 @@ parallel-transform@^1.1.0: inherits "^2.0.3" readable-stream "^2.1.5" -param-case@2.1.x: +param-case@2.1.x, param-case@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc= @@ -20347,6 +20530,14 @@ parseurl@~1.3.2, parseurl@~1.3.3: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== +pascal-case@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-2.0.1.tgz#2d578d3455f660da65eca18ef95b4e0de912761e" + integrity sha1-LVeNNFX2YNpl7KGO+VtODekSdh4= + dependencies: + camel-case "^3.0.0" + upper-case-first "^1.1.0" + pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" @@ -20372,6 +20563,13 @@ path-browserify@~0.0.0: resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== +path-case@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/path-case/-/path-case-2.1.1.tgz#94b8037c372d3fe2906e465bb45e25d226e8eea5" + integrity sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU= + dependencies: + no-case "^2.2.0" + path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" @@ -23739,6 +23937,19 @@ remark-lint@^6.0.0, remark-lint@^6.0.4: dependencies: remark-message-control "^4.0.0" +remark-mdx@^1.0.21: + version "1.0.21" + resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-1.0.21.tgz#cf5a59ad68cce6c1f687953dcf504212fbd32555" + integrity sha512-paYs43yHPkxEuhyWXvRGJdupdurua1ttmGeu5GLqU/qc17BaZklCdNSEjCNXRa2LM0pOFRv0KVJigfA2vfaDEQ== + dependencies: + "@babel/core" "^7.2.2" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.3.2" + "@babel/plugin-syntax-jsx" "^7.2.0" + is-alphabetical "^1.0.2" + remark-parse "^6.0.0" + unified "^7.0.0" + remark-message-control@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/remark-message-control/-/remark-message-control-4.1.1.tgz#a3f0b08dffda484e7196f0539de1488220f1d251" @@ -23791,6 +24002,13 @@ remark-preset-lint-recommended@^3.0.2: remark-lint-no-unused-definitions "^1.0.0" remark-lint-ordered-list-marker-style "^1.0.0" +remark-squeeze-paragraphs@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-3.0.4.tgz#9fe50c3bf3b572dd88754cd426ada007c0b8dc5f" + integrity sha512-Wmz5Yj9q+W1oryo8BV17JrOXZgUKVcpJ2ApE2pwnoHwhFKSk4Wp2PmFNbmJMgYSqAdFwfkoe+TSYop5Fy8wMgA== + dependencies: + mdast-squeeze-paragraphs "^3.0.0" + remark-stringify@^6.0.0: version "6.0.4" resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-6.0.4.tgz#16ac229d4d1593249018663c7bddf28aafc4e088" @@ -24626,6 +24844,14 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" +sentence-case@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-2.1.1.tgz#1f6e2dda39c168bf92d13f86d4a918933f667ed4" + integrity sha1-H24t2jnBaL+S0T+G1KkYkz9mftQ= + dependencies: + no-case "^2.2.0" + upper-case-first "^1.1.2" + serialize-error@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a" @@ -25003,6 +25229,13 @@ smart-buffer@4.0.2: resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.2.tgz#5207858c3815cc69110703c6b94e46c15634395d" integrity sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw== +snake-case@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f" + integrity sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8= + dependencies: + no-case "^2.2.0" + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -25815,6 +26048,13 @@ style-loader@0.23.1, style-loader@^0.23.1: loader-utils "^1.1.0" schema-utils "^1.0.0" +style-to-object@^0.2.1: + version "0.2.2" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.2.2.tgz#3ea3b276bd3fa9da1195fcdcdd03bc52aa2aae01" + integrity sha512-GcbtvfsqyKmIPpHeOHZ5Rmwsx2MDJct4W9apmTGcbPTbpA2FcgTFl2Z43Hm4Qb61MWGPNK8Chki7ITiY7lLOow== + dependencies: + css "2.2.4" + style-unit@^0.6.5: version "0.6.5" resolved "https://registry.npmjs.org/style-unit/-/style-unit-0.6.5.tgz#4c471b1429a3b951bfd881fbf512ca20a19047da" @@ -26014,6 +26254,14 @@ svgo@^1.0.0, svgo@^1.2.1: unquote "~1.1.1" util.promisify "~1.0.0" +swap-case@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-1.1.2.tgz#c39203a4587385fad3c850a0bd1bcafa081974e3" + integrity sha1-w5IDpFhzhfrTyFCgvRvK+ggZdOM= + dependencies: + lower-case "^1.1.1" + upper-case "^1.1.1" + symbol-observable@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" @@ -26432,6 +26680,14 @@ tinycolor2@^1.4.1: resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" integrity sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g= +title-case@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa" + integrity sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o= + dependencies: + no-case "^2.2.0" + upper-case "^1.0.3" + tmp@0.0.28: version "0.0.28" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" @@ -26520,6 +26776,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +to-style@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/to-style/-/to-style-1.3.3.tgz#63a2b70a6f4a7d4fdc2ed57a0be4e7235cb6699c" + integrity sha1-Y6K3Cm9KfU/cLtV6C+TnI1y2aZw= + to-vfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/to-vfile/-/to-vfile-4.0.0.tgz#465ade5fc2b9e97e6c80b854d378a5d0f4b5d04a" @@ -26636,6 +26897,11 @@ tree-sync@^1.2.2: quick-temp "^0.1.5" walk-sync "^0.3.3" +trim-lines@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-1.1.2.tgz#c8adbdbdae21bb5c2766240a661f693afe23e59b" + integrity sha512-3GOuyNeTqk3FAqc3jOJtw7FTjYl94XBR5aD9QnDbK/T4CA9sW/J0l9RoaRPE9wyPP7NF331qnHnvJFBJ+IDkmQ== + trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" @@ -27231,6 +27497,13 @@ unique-string@^1.0.0: dependencies: crypto-random-string "^1.0.0" +unist-builder@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-1.0.4.tgz#e1808aed30bd72adc3607f25afecebef4dd59e17" + integrity sha512-v6xbUPP7ILrT15fHGrNyHc1Xda8H3xVhP7/HAIotHOhVPjH5dCXA097C3Rry1Q2O+HbOLCao4hfPB+EYEjHgVg== + dependencies: + object-assign "^4.1.0" + unist-util-generated@^1.1.0: version "1.1.4" resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-1.1.4.tgz#2261c033d9fc23fae41872cdb7663746e972c1a7" @@ -27248,6 +27521,11 @@ unist-util-is@^2.1.2: resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-2.1.3.tgz#459182db31f4742fceaea88d429693cbf0043d20" integrity sha512-4WbQX2iwfr/+PfM4U3zd2VNXY+dWtZsN1fLnWEi2QQXA4qyDYAZcDMfXUX0Cu6XZUHHAO9q4nyxxLT4Awk1qUA== +unist-util-is@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd" + integrity sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A== + unist-util-position@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-3.0.3.tgz#fff942b879538b242096c148153826664b1ca373" @@ -27260,6 +27538,13 @@ unist-util-remove-position@^1.0.0: dependencies: unist-util-visit "^1.1.0" +unist-util-remove@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/unist-util-remove/-/unist-util-remove-1.0.3.tgz#58ec193dfa84b52d5a055ffbc58e5444eb8031a3" + integrity sha512-mB6nCHCQK0pQffUAcCVmKgIWzG/AXs/V8qpS8K72tMPtOSCMSjDeMc5yN+Ye8rB0FhcE+JvW++o1xRNc0R+++g== + dependencies: + unist-util-is "^3.0.0" + unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1, unist-util-stringify-position@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6" @@ -27279,7 +27564,7 @@ unist-util-visit-parents@^2.0.0: dependencies: unist-util-is "^2.1.2" -unist-util-visit@^1.0.0, unist-util-visit@^1.1.0, unist-util-visit@^1.1.1, unist-util-visit@^1.4.0: +unist-util-visit@^1.0.0, unist-util-visit@^1.1.0, unist-util-visit@^1.1.1, unist-util-visit@^1.3.0, unist-util-visit@^1.4.0: version "1.4.1" resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.1.tgz#4724aaa8486e6ee6e26d7ff3c8685960d560b1e3" integrity sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw== @@ -27369,7 +27654,14 @@ update-notifier@^3.0.0: semver-diff "^2.0.0" xdg-basedir "^3.0.0" -upper-case@^1.1.1: +upper-case-first@^1.1.0, upper-case-first@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-1.1.2.tgz#5d79bedcff14419518fd2edb0a0507c9b6859115" + integrity sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU= + dependencies: + upper-case "^1.1.1" + +upper-case@^1.0.3, upper-case@^1.1.0, upper-case@^1.1.1, upper-case@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= @@ -27886,7 +28178,7 @@ weak@^1.0.1: bindings "^1.2.1" nan "^2.0.5" -web-namespaces@^1.1.2: +web-namespaces@^1.0.0, web-namespaces@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.3.tgz#9bbf5c99ff0908d2da031f1d732492a96571a83f" integrity sha512-r8sAtNmgR0WKOKOxzuSgk09JsHlpKlB+uHi937qypOu3PZ17UxPrierFKDye/uNHjNTTEshu5PId8rojIPj/tA== @@ -29264,3 +29556,8 @@ zone.js@^0.8.29: version "0.8.29" resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.29.tgz#8dce92aa0dd553b50bc5bfbb90af9986ad845a12" integrity sha512-mla2acNCMkWXBD+c+yeUrBUrzOxYMNFdQ6FGfigGGtEVBPJx07BQeJekjt9DmH1FtZek4E9rE1eRR9qQpxACOQ== + +zwitch@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.4.tgz#93b1b993b13c8926753a41afaf8f27bbfac6be8b" + integrity sha512-YO803/X+13GNaZB7fVopjvHH0uWQKgJkgKnU1YCjxShjKGVuN9PPHHW8g+uFDpkHpSTNi3rCMKMewIcbC1BAYg==