diff --git a/README.md b/README.md index f3a738a..95429a5 100644 --- a/README.md +++ b/README.md @@ -268,6 +268,7 @@ stories.add( | docgenCollectionName | string or null | Specify the docgen collection name to use. All docgen information will be collected into this global object. Set to `null` to disable. Defaults to `STORYBOOK_REACT_CLASSES` for use with the Storybook Info Addon. https://github.com/gongreg/react-storybook-addon-docgen | | setDisplayName | boolean | Automatically set the components' display name. If you want to set display names yourself or are using another plugin to do this, you should disable this option. Defaults to `true`. This is used to preserve component display names during a production build of Storybook. | | shouldExtractLiteralValuesFromEnum | boolean | If set to true, string enums and unions will be converted to docgen enum format. Useful if you use Storybook and want to generate knobs automatically using [addon-smart-knobs](https://github.com/storybookjs/addon-smart-knobs). https://github.com/styleguidist/react-docgen-typescript#parseroptions | +| shouldExtractValuesFromUnion | boolean | If set to true, every unions will be converted to docgen enum format. https://github.com/styleguidist/react-docgen-typescript#parseroptions | | savePropValueAsString | boolean | If set to true, defaultValue to props will be string. https://github.com/styleguidist/react-docgen-typescript#parseroptions | | typePropName | string | Specify the name of the property for docgen info prop type. | diff --git a/package.json b/package.json index f60fc15..69b7295 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "dependencies": { "@webpack-contrib/schema-utils": "^1.0.0-beta.0", "loader-utils": "^1.2.3", - "react-docgen-typescript": "^1.15.0" + "react-docgen-typescript": "^1.20.1" }, "peerDependencies": { "typescript": "*" diff --git a/src/LoaderOptions.ts b/src/LoaderOptions.ts index abf3756..4729318 100644 --- a/src/LoaderOptions.ts +++ b/src/LoaderOptions.ts @@ -64,6 +64,12 @@ export default interface LoaderOptions { * */ shouldExtractLiteralValuesFromEnum?: boolean; + /** + * If set to true, every unions will be converted to docgen enum format. + * @see https://github.com/styleguidist/react-docgen-typescript#parseroptions + * */ + shouldExtractValuesFromUnion?: boolean; + /** * If set to true, defaultValue to props will be string. * @see https://github.com/styleguidist/react-docgen-typescript#parseroptions diff --git a/src/__fixtures__/components/DefaultPropValue.tsx b/src/__fixtures__/components/DefaultPropValue.tsx index a6c396e..c74070e 100644 --- a/src/__fixtures__/components/DefaultPropValue.tsx +++ b/src/__fixtures__/components/DefaultPropValue.tsx @@ -1,5 +1,7 @@ import * as React from "react"; +type FontWeight = "normal" | "bold"; + interface DefaultPropValueComponentProps { /** * Button color. @@ -8,6 +10,13 @@ interface DefaultPropValueComponentProps { **/ color: "blue" | "green"; + /** + * The font weight to use on text + * + * @default normal + */ + weight?: FontWeight; + /** * Button counter. */ @@ -25,7 +34,13 @@ interface DefaultPropValueComponentProps { export const DefaultPropValueComponent: React.SFC< DefaultPropValueComponentProps > = props => ( - diff --git a/src/__snapshots__/generateDocgenCodeBlock.spec.ts.snap b/src/__snapshots__/generateDocgenCodeBlock.spec.ts.snap index 4385750..8da8ea9 100644 --- a/src/__snapshots__/generateDocgenCodeBlock.spec.ts.snap +++ b/src/__snapshots__/generateDocgenCodeBlock.spec.ts.snap @@ -30,6 +30,8 @@ catch (__react_docgen_typescript_loader_error) { }" exports[`component fixture DefaultPropValue.tsx has code block generated 1`] = ` "import * as React from \\"react\\"; +type FontWeight = \\"normal\\" | \\"bold\\"; + interface DefaultPropValueComponentProps { /** * Button color. @@ -38,6 +40,13 @@ interface DefaultPropValueComponentProps { **/ color: \\"blue\\" | \\"green\\"; + /** + * The font weight to use on text + * + * @default normal + */ + weight?: FontWeight; + /** * Button counter. */ @@ -55,7 +64,13 @@ interface DefaultPropValueComponentProps { export const DefaultPropValueComponent: React.SFC< DefaultPropValueComponentProps > = props => ( - @@ -69,7 +84,7 @@ try { // @ts-ignore DefaultPropValueComponent.displayName = \\"DefaultPropValueComponent\\"; // @ts-ignore - DefaultPropValueComponent.__docgenInfo = { \\"description\\": \\"Component with a prop with a default value.\\", \\"displayName\\": \\"DefaultPropValueComponent\\", \\"props\\": { \\"color\\": { \\"defaultValue\\": { value: \\"blue\\" }, \\"description\\": \\"Button color.\\", \\"name\\": \\"color\\", \\"required\\": true, \\"type\\": { \\"name\\": \\"\\\\\\"blue\\\\\\" | \\\\\\"green\\\\\\"\\" } }, \\"counter\\": { \\"defaultValue\\": { value: 123 }, \\"description\\": \\"Button counter.\\", \\"name\\": \\"counter\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"number\\" } }, \\"disabled\\": { \\"defaultValue\\": { value: false }, \\"description\\": \\"Button disabled.\\", \\"name\\": \\"disabled\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"boolean\\" } } } }; + DefaultPropValueComponent.__docgenInfo = { \\"description\\": \\"Component with a prop with a default value.\\", \\"displayName\\": \\"DefaultPropValueComponent\\", \\"props\\": { \\"color\\": { \\"defaultValue\\": { value: \\"blue\\" }, \\"description\\": \\"Button color.\\", \\"name\\": \\"color\\", \\"required\\": true, \\"type\\": { \\"name\\": \\"\\\\\\"blue\\\\\\" | \\\\\\"green\\\\\\"\\" } }, \\"weight\\": { \\"defaultValue\\": { value: \\"normal\\" }, \\"description\\": \\"The font weight to use on text\\", \\"name\\": \\"weight\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"FontWeight\\" } }, \\"counter\\": { \\"defaultValue\\": { value: 123 }, \\"description\\": \\"Button counter.\\", \\"name\\": \\"counter\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"number\\" } }, \\"disabled\\": { \\"defaultValue\\": { value: false }, \\"description\\": \\"Button disabled.\\", \\"name\\": \\"disabled\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"boolean\\" } } } }; } catch (__react_docgen_typescript_loader_error) { }" `; @@ -231,6 +246,132 @@ catch (__react_docgen_typescript_loader_error) { }" exports[`generates value info for enums 1`] = ` "import * as React from \\"react\\"; +type FontWeight = \\"normal\\" | \\"bold\\"; + +interface DefaultPropValueComponentProps { + /** + * Button color. + * + * @default blue + **/ + color: \\"blue\\" | \\"green\\"; + + /** + * The font weight to use on text + * + * @default normal + */ + weight?: FontWeight; + + /** + * Button counter. + */ + counter: number; + + /** + * Button disabled. + */ + disabled: boolean; +} + +/** + * Component with a prop with a default value. + */ +export const DefaultPropValueComponent: React.SFC< + DefaultPropValueComponentProps +> = props => ( + +); + +DefaultPropValueComponent.defaultProps = { + counter: 123, + disabled: false, +}; +try { + // @ts-ignore + DefaultPropValueComponent.displayName = \\"DefaultPropValueComponent\\"; + // @ts-ignore + DefaultPropValueComponent.__docgenInfo = { \\"description\\": \\"Component with a prop with a default value.\\", \\"displayName\\": \\"DefaultPropValueComponent\\", \\"props\\": { \\"color\\": { \\"defaultValue\\": { value: \\"blue\\" }, \\"description\\": \\"Button color.\\", \\"name\\": \\"color\\", \\"required\\": true, \\"type\\": { \\"name\\": \\"enum\\", \\"value\\": [{ \\"value\\": \\"\\\\\\"blue\\\\\\"\\" }, { \\"value\\": \\"\\\\\\"green\\\\\\"\\" }] } }, \\"weight\\": { \\"defaultValue\\": { value: \\"normal\\" }, \\"description\\": \\"The font weight to use on text\\", \\"name\\": \\"weight\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"enum\\", \\"value\\": [{ \\"value\\": \\"\\\\\\"normal\\\\\\"\\" }, { \\"value\\": \\"\\\\\\"bold\\\\\\"\\" }] } }, \\"counter\\": { \\"defaultValue\\": { value: 123 }, \\"description\\": \\"Button counter.\\", \\"name\\": \\"counter\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"number\\" } }, \\"disabled\\": { \\"defaultValue\\": { value: false }, \\"description\\": \\"Button disabled.\\", \\"name\\": \\"disabled\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"boolean\\" } } } }; +} +catch (__react_docgen_typescript_loader_error) { }" +`; + +exports[`generates value info for unions 1`] = ` +"import * as React from \\"react\\"; + +type FontWeight = \\"normal\\" | \\"bold\\"; + +interface DefaultPropValueComponentProps { + /** + * Button color. + * + * @default blue + **/ + color: \\"blue\\" | \\"green\\"; + + /** + * The font weight to use on text + * + * @default normal + */ + weight?: FontWeight; + + /** + * Button counter. + */ + counter: number; + + /** + * Button disabled. + */ + disabled: boolean; +} + +/** + * Component with a prop with a default value. + */ +export const DefaultPropValueComponent: React.SFC< + DefaultPropValueComponentProps +> = props => ( + +); + +DefaultPropValueComponent.defaultProps = { + counter: 123, + disabled: false, +}; +try { + // @ts-ignore + DefaultPropValueComponent.displayName = \\"DefaultPropValueComponent\\"; + // @ts-ignore + DefaultPropValueComponent.__docgenInfo = { \\"description\\": \\"Component with a prop with a default value.\\", \\"displayName\\": \\"DefaultPropValueComponent\\", \\"props\\": { \\"color\\": { \\"defaultValue\\": { value: \\"blue\\" }, \\"description\\": \\"Button color.\\", \\"name\\": \\"color\\", \\"required\\": true, \\"type\\": { \\"name\\": \\"enum\\", \\"value\\": [{ \\"value\\": \\"\\\\\\"blue\\\\\\"\\" }, { \\"value\\": \\"\\\\\\"green\\\\\\"\\" }] } }, \\"weight\\": { \\"defaultValue\\": { value: \\"normal\\" }, \\"description\\": \\"The font weight to use on text\\", \\"name\\": \\"weight\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"enum\\", \\"value\\": [{ \\"value\\": \\"\\\\\\"normal\\\\\\"\\" }, { \\"value\\": \\"\\\\\\"bold\\\\\\"\\" }] } }, \\"counter\\": { \\"defaultValue\\": { value: 123 }, \\"description\\": \\"Button counter.\\", \\"name\\": \\"counter\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"number\\" } }, \\"disabled\\": { \\"defaultValue\\": { value: false }, \\"description\\": \\"Button disabled.\\", \\"name\\": \\"disabled\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"enum\\", \\"value\\": [{ \\"value\\": \\"false\\" }, { \\"value\\": \\"true\\" }] } } } }; +} +catch (__react_docgen_typescript_loader_error) { }" +`; + +exports[`preserves type name for unions 1`] = ` +"import * as React from \\"react\\"; + +type FontWeight = \\"normal\\" | \\"bold\\"; + interface DefaultPropValueComponentProps { /** * Button color. @@ -239,6 +380,13 @@ interface DefaultPropValueComponentProps { **/ color: \\"blue\\" | \\"green\\"; + /** + * The font weight to use on text + * + * @default normal + */ + weight?: FontWeight; + /** * Button counter. */ @@ -256,7 +404,13 @@ interface DefaultPropValueComponentProps { export const DefaultPropValueComponent: React.SFC< DefaultPropValueComponentProps > = props => ( - @@ -270,7 +424,7 @@ try { // @ts-ignore DefaultPropValueComponent.displayName = \\"DefaultPropValueComponent\\"; // @ts-ignore - DefaultPropValueComponent.__docgenInfo = { \\"description\\": \\"Component with a prop with a default value.\\", \\"displayName\\": \\"DefaultPropValueComponent\\", \\"props\\": { \\"color\\": { \\"defaultValue\\": { value: \\"blue\\" }, \\"description\\": \\"Button color.\\", \\"name\\": \\"color\\", \\"required\\": true, \\"type\\": { \\"name\\": \\"enum\\", \\"value\\": [{ \\"value\\": \\"\\\\\\"blue\\\\\\"\\" }, { \\"value\\": \\"\\\\\\"green\\\\\\"\\" }] } }, \\"counter\\": { \\"defaultValue\\": { value: 123 }, \\"description\\": \\"Button counter.\\", \\"name\\": \\"counter\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"number\\" } }, \\"disabled\\": { \\"defaultValue\\": { value: false }, \\"description\\": \\"Button disabled.\\", \\"name\\": \\"disabled\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"boolean\\" } } } }; + DefaultPropValueComponent.__docgenInfo = { \\"description\\": \\"Component with a prop with a default value.\\", \\"displayName\\": \\"DefaultPropValueComponent\\", \\"props\\": { \\"color\\": { \\"defaultValue\\": { value: \\"blue\\" }, \\"description\\": \\"Button color.\\", \\"name\\": \\"color\\", \\"required\\": true, \\"type\\": { \\"name\\": \\"\\\\\\"blue\\\\\\" | \\\\\\"green\\\\\\"\\" } }, \\"weight\\": { \\"defaultValue\\": { value: \\"normal\\" }, \\"description\\": \\"The font weight to use on text\\", \\"name\\": \\"weight\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"FontWeight\\" } }, \\"counter\\": { \\"defaultValue\\": { value: 123 }, \\"description\\": \\"Button counter.\\", \\"name\\": \\"counter\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"number\\" } }, \\"disabled\\": { \\"defaultValue\\": { value: false }, \\"description\\": \\"Button disabled.\\", \\"name\\": \\"disabled\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"boolean\\" } } } }; } catch (__react_docgen_typescript_loader_error) { }" `; diff --git a/src/__snapshots__/webpack.spec.ts.snap b/src/__snapshots__/webpack.spec.ts.snap index bc82a64..bb4361c 100644 --- a/src/__snapshots__/webpack.spec.ts.snap +++ b/src/__snapshots__/webpack.spec.ts.snap @@ -110,7 +110,10 @@ var React = __importStar(__webpack_require__(/*! react */ \\"react\\")); /** * Component with a prop with a default value. */ -exports.DefaultPropValueComponent = function (props) { return (React.createElement(\\"button\\", { disabled: props.disabled, style: { backgroundColor: props.color } }, +exports.DefaultPropValueComponent = function (props) { return (React.createElement(\\"button\\", { disabled: props.disabled, style: { + backgroundColor: props.color, + fontWeight: props.weight || \\"normal\\", + } }, props.counter, props.children)); }; exports.DefaultPropValueComponent.defaultProps = { @@ -121,7 +124,7 @@ try { // @ts-ignore exports.DefaultPropValueComponent.displayName = \\"DefaultPropValueComponent\\"; // @ts-ignore - exports.DefaultPropValueComponent.__docgenInfo = { \\"description\\": \\"Component with a prop with a default value.\\", \\"displayName\\": \\"DefaultPropValueComponent\\", \\"props\\": { \\"color\\": { \\"defaultValue\\": { value: \\"blue\\" }, \\"description\\": \\"Button color.\\", \\"name\\": \\"color\\", \\"required\\": true, \\"type\\": { \\"name\\": \\"\\\\\\"blue\\\\\\" | \\\\\\"green\\\\\\"\\" } }, \\"counter\\": { \\"defaultValue\\": { value: 123 }, \\"description\\": \\"Button counter.\\", \\"name\\": \\"counter\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"number\\" } }, \\"disabled\\": { \\"defaultValue\\": { value: false }, \\"description\\": \\"Button disabled.\\", \\"name\\": \\"disabled\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"boolean\\" } } } }; + exports.DefaultPropValueComponent.__docgenInfo = { \\"description\\": \\"Component with a prop with a default value.\\", \\"displayName\\": \\"DefaultPropValueComponent\\", \\"props\\": { \\"color\\": { \\"defaultValue\\": { value: \\"blue\\" }, \\"description\\": \\"Button color.\\", \\"name\\": \\"color\\", \\"required\\": true, \\"type\\": { \\"name\\": \\"\\\\\\"blue\\\\\\" | \\\\\\"green\\\\\\"\\" } }, \\"weight\\": { \\"defaultValue\\": { value: \\"normal\\" }, \\"description\\": \\"The font weight to use on text\\", \\"name\\": \\"weight\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"FontWeight\\" } }, \\"counter\\": { \\"defaultValue\\": { value: 123 }, \\"description\\": \\"Button counter.\\", \\"name\\": \\"counter\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"number\\" } }, \\"disabled\\": { \\"defaultValue\\": { value: false }, \\"description\\": \\"Button disabled.\\", \\"name\\": \\"disabled\\", \\"required\\": false, \\"type\\": { \\"name\\": \\"boolean\\" } } } }; // @ts-ignore if (typeof STORYBOOK_REACT_CLASSES !== \\"undefined\\") // @ts-ignore diff --git a/src/generateDocgenCodeBlock.spec.ts b/src/generateDocgenCodeBlock.spec.ts index b9e512c..b9d1c6a 100644 --- a/src/generateDocgenCodeBlock.spec.ts +++ b/src/generateDocgenCodeBlock.spec.ts @@ -59,3 +59,23 @@ it("generates value info for enums", () => { ), ).toMatchSnapshot(); }); + +it("generates value info for unions", () => { + expect( + generateDocgenCodeBlock( + getGeneratorOptions({ shouldExtractValuesFromUnion: true })( + "DefaultPropValue.tsx", + ), + ), + ).toMatchSnapshot(); +}); + +it("preserves type name for unions", () => { + expect( + generateDocgenCodeBlock( + getGeneratorOptions({ shouldExtractValuesFromUnion: false })( + "DefaultPropValue.tsx", + ), + ), + ).toMatchSnapshot(); +}); diff --git a/src/loader.ts b/src/loader.ts index 1693048..c0809f9 100644 --- a/src/loader.ts +++ b/src/loader.ts @@ -81,6 +81,7 @@ function processResource( : options.propFilter, shouldExtractLiteralValuesFromEnum: options.shouldExtractLiteralValuesFromEnum, + shouldExtractValuesFromUnion: options.shouldExtractValuesFromUnion, savePropValueAsString: options.savePropValueAsString, }; diff --git a/src/validateOptions.ts b/src/validateOptions.ts index 03efd80..cd23a8b 100644 --- a/src/validateOptions.ts +++ b/src/validateOptions.ts @@ -61,6 +61,10 @@ const schema = { type: "boolean", }, + shouldExtractValuesFromUnion: { + type: "boolean", + }, + savePropValueAsString: { type: "boolean", }, diff --git a/yarn.lock b/yarn.lock index c279c1d..22624c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3979,10 +3979,10 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-docgen-typescript@^1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-1.15.0.tgz#963f14210841f9b51ed18c65152a6cc37f1c3184" - integrity sha512-8xObdkRQbrc0505tEdVRO+pdId8pKFyD6jhLYM9FDdceKma+iB+a17Dk7e3lPRBRh8ArQLCedOCOfN/bO338kw== +react-docgen-typescript@^1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-1.20.1.tgz#774ed8b4a7111acaaa536cad4cfd61c504a46f7e" + integrity sha512-vU6puLsSwfCS+nI/6skQ52sJIx/uW7+9aMI/V/zPHAXr6s8OQzD5LeL9rXx/Hdt2aNfm4yTX9oJ8ClH/5PKQNg== react-is@^16.8.4: version "16.9.0"