Addon-docs: Support jsdoc params to describe function signature (#8660)

Addon-docs: Support jsdoc params to describe function signature
This commit is contained in:
Michael Shilman 2019-11-01 23:40:33 +08:00 committed by GitHub
commit 4aed2feec4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 2378 additions and 338 deletions

View File

@ -14,6 +14,8 @@ scripts/storage
*.d.ts
examples/ember-cli/.storybook/preview-head.html
examples/official-storybook/tests/addon-jest.test.js
examples/cra-ts-kitchen-sink/*.json
examples/cra-ts-kitchen-sink/public/*.json
!.remarkrc.js
!.babelrc.js

View File

@ -51,6 +51,7 @@
"@storybook/source-loader": "5.3.0-alpha.35",
"@storybook/theming": "5.3.0-alpha.35",
"core-js": "^3.0.1",
"doctrine": "^3.0.0",
"global": "^4.3.2",
"js-string-escape": "^1.0.1",
"lodash": "^4.17.15",
@ -59,6 +60,9 @@
"ts-dedent": "^1.1.0"
},
"devDependencies": {
"@types/doctrine": "^0.0.3",
"@types/enzyme": "^3.10.3",
"@types/jest": "^24.0.11",
"@types/prop-types": "^15.5.9",
"@types/util-deprecate": "^1.0.0",
"@types/webpack-env": "^1.14.0"

View File

@ -1,8 +1,12 @@
/* eslint-disable no-underscore-dangle,react/forbid-foreign-prop-types */
import PropTypes from 'prop-types';
import { isForwardRef, isMemo } from 'react-is';
import { PropDef } from '@storybook/components';
import { PropDefGetter, PropsExtractor, propsFromDocgen, hasDocgen } from '../../lib/docgenUtils';
import {
PropDefGetter,
PropsExtractor,
extractPropsFromDocgen,
hasDocgen,
} from '../../lib/docgenUtils';
export interface PropDefMap {
[p: string]: PropDef;
@ -18,47 +22,6 @@ Object.keys(PropTypes).forEach(typeName => {
propTypesMap.set(type.isRequired, typeName);
});
const propsFromPropTypes: PropDefGetter = (type, section) => {
const props: PropDefMap = {};
if (type.propTypes) {
Object.keys(type.propTypes).forEach(property => {
const typeInfo = type.propTypes[property];
const required = typeInfo.isRequired === undefined;
const docgenInfo =
type.__docgenInfo && type.__docgenInfo[section] && type.__docgenInfo[section][property];
const description = docgenInfo ? docgenInfo.description : null;
let propType = propTypesMap.get(typeInfo) || 'other';
if (propType === 'other') {
if (docgenInfo && docgenInfo.type) {
propType = docgenInfo.type.name;
}
}
props[property] = { name: property, type: propType, required, description };
});
}
if (type.defaultProps) {
Object.keys(type.defaultProps).forEach(property => {
const value = type.defaultProps[property];
if (value === undefined) {
return;
}
if (!props[property]) {
props[property] = { name: property, type: 'any', required: false };
}
props[property].defaultValue = value;
});
}
return Object.values(props);
};
export const getPropDefs: PropDefGetter = (type, section) => {
let processedType = type;
if (!hasDocgen(type) && !type.propTypes) {
@ -70,9 +33,8 @@ export const getPropDefs: PropDefGetter = (type, section) => {
processedType = type.type().type;
}
}
return hasDocgen(processedType)
? propsFromDocgen(processedType, section)
: propsFromPropTypes(processedType, section);
return extractPropsFromDocgen(processedType, section);
};
export const extractProps: PropsExtractor = component => ({

View File

@ -1,5 +1,5 @@
import { PropDef } from '@storybook/components';
import { PropsExtractor, propsFromDocgen, hasDocgen } from '../../lib/docgenUtils';
import { PropsExtractor, extractPropsFromDocgen, hasDocgen } from '../../lib/docgenUtils';
const SECTIONS = ['props', 'events', 'slots'];
@ -9,7 +9,7 @@ export const extractProps: PropsExtractor = component => {
}
const sections: Record<string, PropDef[]> = {};
SECTIONS.forEach(section => {
sections[section] = propsFromDocgen(component, section);
sections[section] = extractPropsFromDocgen(component, section);
});
return { sections };
};

View File

@ -1,10 +1,11 @@
/* eslint-disable no-underscore-dangle */
import { PropDef, PropsTableProps } from '@storybook/components';
import { Component } from '../blocks/shared';
import { getTypeSystemHandler, getPropTypeSystem } from './type-system-handlers';
export type PropsExtractor = (component: Component) => PropsTableProps | null;
export type PropDefGetter = (type: Component, section: string) => PropDef[] | null;
export type PropDefGetter = (type: Component, section: string) => PropDef[];
export const str = (o: any) => {
if (!o) {
@ -23,25 +24,28 @@ export const hasDocgenSection = (obj: any, section: string) =>
obj.__docgenInfo[section] &&
Object.keys(obj.__docgenInfo[section]).length > 0;
export const propsFromDocgen: PropDefGetter = (type, section) => {
export const extractPropsFromDocgen: PropDefGetter = (type, section) => {
const props: Record<string, PropDef> = {};
const docgenInfoProps = type.__docgenInfo[section];
if (!docgenInfoProps) {
return null;
return [];
}
Object.keys(docgenInfoProps).forEach(property => {
const docgenInfoProp = docgenInfoProps[property];
const defaultValueDesc = docgenInfoProp.defaultValue || {};
const propType = docgenInfoProp.flowType || docgenInfoProp.type || 'other';
const propKeys = Object.keys(docgenInfoProps);
if (propKeys.length === 0) {
return [];
}
props[property] = {
name: property,
type: propType,
required: docgenInfoProp.required,
description: docgenInfoProp.description,
defaultValue: defaultValueDesc.value,
};
// Assuming the props for a given type will all have the same type system.
const typeSystem = getPropTypeSystem(docgenInfoProps[propKeys[0]]);
const typeSystemHandler = getTypeSystemHandler(typeSystem);
propKeys.forEach(propKey => {
const docgenInfoProp = docgenInfoProps[propKey];
const propDef = typeSystemHandler(propKey, docgenInfoProp);
props[propKey] = propDef;
});
return Object.values(props);

View File

@ -0,0 +1,24 @@
import doctrine from 'doctrine';
export interface JsDocAst {
description?: string;
tags: any[];
}
export function parseComment(comment: string): JsDocAst {
let ast;
try {
ast = doctrine.parse(comment, {
tags: ['param', 'arg', 'argument', 'returns'],
sloppy: true,
});
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
throw new Error('Cannot parse JSDoc tags.');
}
return ast;
}

View File

@ -0,0 +1,717 @@
import { propTypesHandler, tsHandler, flowHandler, DocgenInfo } from './type-system-handlers';
const DEFAULT_PROP_NAME = 'propName';
const PROP_TYPE_FUNC_TYPE = {
name: 'func',
};
function createPropTypesDocgenInfo(overrides: Record<string, any> = {}): DocgenInfo {
return {
type: { name: 'string' },
required: true,
description: 'A string prop',
defaultValue: {
value: 'default string',
},
...overrides,
};
}
function createTypeScriptDocgenInfo(overrides: Record<string, any> = {}): DocgenInfo {
return {
tsType: { name: 'string' },
required: true,
description: 'A string prop',
defaultValue: {
value: 'default string',
},
...overrides,
};
}
function createFlowDocgenInfo(overrides: Record<string, any> = {}): DocgenInfo {
return {
flowType: { name: 'string' },
required: true,
description: 'A string prop',
defaultValue: {
value: 'default string',
},
...overrides,
};
}
describe('prop-types handler', () => {
it('should map defaults docgen info properly', () => {
const docgenInfo = createPropTypesDocgenInfo();
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.name).toBe(DEFAULT_PROP_NAME);
expect(propDef.type.name).toBe(docgenInfo.type.name);
expect(propDef.description).toBe(docgenInfo.description);
expect(propDef.required).toBe(docgenInfo.required);
expect(propDef.defaultValue).toBe(docgenInfo.defaultValue.value);
});
describe('when the prop is not a function', () => {
it('should handle prop without a description', () => {
const docgenInfo = createPropTypesDocgenInfo({
description: undefined,
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.description).toBeUndefined();
});
it('should clean the description', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: {
name: 'string',
},
description: 'onClick description\n@param {SyntheticEvent} event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.description).toBe('onClick description');
});
it('should have an empty description when the description only contains JSDoc', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: {
name: 'string',
},
description: '@param event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.description).toBe('');
});
it('should not remove newline characters of multilines description without JSDoc tags', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: {
name: 'string',
},
description: 'onClick description\nis a\nmulti-lines\ndescription',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.description).toBe('onClick description\nis a\nmulti-lines\ndescription');
});
it('should not remove newline characters of multilines description with JSDoc tags', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: {
name: 'string',
},
description: 'onClick description\nis a\nmulti-lines\ndescription\n@param event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.description).toBe('onClick description\nis a\nmulti-lines\ndescription');
});
it('should not remove markdown from description without JSDoc tags', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: {
name: 'string',
},
description: 'onClick *emphasis*, **strong**, `formatted` description.',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.description).toBe('onClick *emphasis*, **strong**, `formatted` description.');
});
it('should not remove markdown from description with JSDoc tags', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: {
name: 'string',
},
description: 'onClick *emphasis*, **strong**, `formatted` description.\n@param event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.description).toBe('onClick *emphasis*, **strong**, `formatted` description.');
});
it('should not remove @ characters that does not match JSDoc tags', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: {
name: 'string',
},
description: 'onClick @description@',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.description).toBe('onClick @description@');
});
});
describe('when the prop is a function', () => {
it("should have func as type when the props doesn't have a description", () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: undefined,
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.description).toBeUndefined();
expect(propDef.type.name).toBe('func');
});
it('should have func as type when the prop have a description without JSDoc', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('func');
expect(propDef.description).toBe('onClick description');
});
it('should have an empty description when the description only contains JSDoc', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: '@param event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.description).toBe('');
});
describe('when the description contains a @param tag', () => {
it('should have func as type when it is an invalid @param tag', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('func');
expect(propDef.description).toBe('onClick description');
});
it('should have a func signature with a single arg as type when it is a @param tag with a name', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event)');
expect(propDef.description).toBe('onClick description');
});
it('should have a func signature with a single arg as type when it is a @param tag with a name and a type', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {SyntheticEvent} event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: SyntheticEvent)');
expect(propDef.description).toBe('onClick description');
});
it('should have a func signature with a single arg as type when it is a @param tag with a name, a type and a desc', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description:
'onClick description\n@param {SyntheticEvent} event - Original SyntheticEvent',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: SyntheticEvent)');
expect(propDef.description).toBe('onClick description');
});
it('should have func as type when it is @param tag without a name 1', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param - Original SyntheticEvent',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('func');
expect(propDef.description).toBe('onClick description');
});
it('should have func as type when it is @param tag without a name 2', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {SyntheticEvent} - Original SyntheticEvent',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('func');
expect(propDef.description).toBe('onClick description');
});
it('should support param of record type with a single field', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {{a: number}} event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: ({a: number}))');
expect(propDef.description).toBe('onClick description');
});
it('should support param of record type with multiple fields', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {{a: number, b: string}} event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: ({a: number, b: string}))');
expect(propDef.description).toBe('onClick description');
});
it('should support param of record type with a field having only a name', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {{a}} event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: ({a}))');
expect(propDef.description).toBe('onClick description');
});
it('should support param of union type', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {(number|boolean)} event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: (number|boolean))');
expect(propDef.description).toBe('onClick description');
});
it('should support param of array type', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {number[]} event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: number[])');
expect(propDef.description).toBe('onClick description');
});
it('should support param of untyped array type', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {[]} event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: [])');
expect(propDef.description).toBe('onClick description');
});
it('should support param with a nullable type', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {?number} event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: number)');
expect(propDef.description).toBe('onClick description');
});
it('should support param with a non nullable type', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {!number} event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: number)');
expect(propDef.description).toBe('onClick description');
});
it('should support optional param 1', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {number} [event]',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: number)');
expect(propDef.description).toBe('onClick description');
});
it('should support optional param 2', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {number=} event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: number)');
expect(propDef.description).toBe('onClick description');
});
it('should support param of type any', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {*} event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: any)');
expect(propDef.description).toBe('onClick description');
});
it('should support multilines description when there is a @param', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\nis a\nmulti-lines\ndescription\n@param event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event)');
expect(propDef.description).toBe('onClick description\nis a\nmulti-lines\ndescription');
});
it('should support multilines @param description', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description:
'onClick description\n@param event - This is my param\nmultiline description\n@param customData',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event, customData)');
expect(propDef.description).toBe('onClick description');
});
it('should autofix missing space between the param name and the description separator', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description:
'onClick description\n@param {SyntheticEvent} event- Original SyntheticEvent',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: SyntheticEvent)');
expect(propDef.description).toBe('onClick description');
});
it('should autofix param name ending with . followed by a @returns tag', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param {SyntheticEvent} event.\n',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: SyntheticEvent)');
expect(propDef.description).toBe('onClick description');
});
});
describe('when the description contains multiple @param tags', () => {
it('should have a func signature with multiple args as type', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description:
'onClick description\n@param {SyntheticEvent} event\n@param {string} customData',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: SyntheticEvent, customData: string)');
expect(propDef.description).toBe('onClick description');
});
it('should ignore invalid @param tags', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description:
'onClick description\n@param {SyntheticEvent} event\n@param {string} customData\n@param {SyntheticEvent} - Original event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: SyntheticEvent, customData: string)');
expect(propDef.description).toBe('onClick description');
});
});
it('should support @arg alias', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@arg event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event)');
expect(propDef.description).toBe('onClick description');
});
it('should support @argument alias', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@argument event',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event)');
expect(propDef.description).toBe('onClick description');
});
describe('when the description contains a @returns tag', () => {
it('should have func as type when it is an invalid @returns tag', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@returns',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('func');
expect(propDef.description).toBe('onClick description');
});
it('should have a func signature with a return type as type when it is a @returns tag with a type', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@returns {string}',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('() => string');
expect(propDef.description).toBe('onClick description');
});
it('should have a func signature with a return type as type when it is a @returns tag with a type and a description', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@returns {string} - A custom return type',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('() => string');
expect(propDef.description).toBe('onClick description');
});
it('should have func as type when it is a @returns tag without a type and there is no params.', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@returns - A custom return type',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('func');
expect(propDef.description).toBe('onClick description');
});
it('should have no return type when it is a @returns tag without a type and there is params.', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@param event\n@returns - A custom return type',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event)');
expect(propDef.description).toBe('onClick description');
});
it('should have a full signature as type when there is a @param and a @returns tag 1', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description:
'onClick description\n@param {SyntheticEvent} event - Original event.\n@returns {string}',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: SyntheticEvent) => string');
expect(propDef.description).toBe('onClick description');
});
it('should have a full signature as type when there is a @param and a @returns tag 2', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description:
'onClick description\n@param {SyntheticEvent} event - Original event.\n@param {string} customData\n@returns {string}',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: SyntheticEvent, customData: string) => string');
expect(propDef.description).toBe('onClick description');
});
it('should only consider the last @returns tag when there is more than one', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@returns {string}\n@returns {integer}',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('() => integer');
expect(propDef.description).toBe('onClick description');
});
it('should support returns of record type', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@returns {{a: number, b: string}}',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('() => ({a: number, b: string})');
expect(propDef.description).toBe('onClick description');
});
it('should support returns of array type', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@returns {integer[]}',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('() => integer[]');
expect(propDef.description).toBe('onClick description');
});
it('should support returns of union type', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@returns {(number|boolean)}',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('() => (number|boolean)');
expect(propDef.description).toBe('onClick description');
});
it('should support returns of type any', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@returns {*}',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('() => any');
expect(propDef.description).toBe('onClick description');
});
it('should support returns of type void', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description: 'onClick description\n@returns {void}',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('() => void');
expect(propDef.description).toBe('onClick description');
});
});
it('should remove extra newline characters between tags', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description:
'onClick description\n@param {SyntheticEvent} event - Original event.\n \n \n \n@returns {string}',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: SyntheticEvent) => string');
expect(propDef.description).toBe('onClick description');
});
it('should ignore unsupported JSDoc tags', () => {
const docgenInfo = createPropTypesDocgenInfo({
type: PROP_TYPE_FUNC_TYPE,
description:
'onClick description\n@param {SyntheticEvent} event\n@type {number}\n@returns {string}\n@version 2',
});
const propDef = propTypesHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.type.name).toBe('(event: SyntheticEvent) => string');
expect(propDef.description).toBe('onClick description');
});
});
});
describe('ts handler', () => {
it('should map defaults docgen info properly', () => {
const docgenInfo = createTypeScriptDocgenInfo();
const propDef = tsHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.name).toBe(DEFAULT_PROP_NAME);
expect(propDef.type.name).toBe(docgenInfo.tsType.name);
expect(propDef.description).toBe(docgenInfo.description);
expect(propDef.required).toBe(docgenInfo.required);
expect(propDef.defaultValue).toBe(docgenInfo.defaultValue.value);
});
});
describe('flow handler', () => {
it('should map defaults docgen info properly', () => {
const docgenInfo = createFlowDocgenInfo();
const propDef = flowHandler(DEFAULT_PROP_NAME, docgenInfo);
expect(propDef.name).toBe(DEFAULT_PROP_NAME);
expect(propDef.type.name).toBe(docgenInfo.flowType.name);
expect(propDef.description).toBe(docgenInfo.description);
expect(propDef.required).toBe(docgenInfo.required);
expect(propDef.defaultValue).toBe(docgenInfo.defaultValue.value);
});
});

View File

@ -0,0 +1,259 @@
import { PropDef } from '@storybook/components';
import { isNil } from 'lodash';
import { parseComment, JsDocAst } from './jsdoc-parser';
export interface DocgenInfo {
type?: {
name: string;
};
flowType?: any;
tsType?: any;
required: boolean;
description?: string;
defaultValue?: {
value: string;
};
}
interface JsDocParamTag {
name: string;
type?: string;
description?: string;
}
interface JsDocReturnsTag {
type?: string;
description?: string;
}
interface ExtractedJsDocTags {
params: JsDocParamTag[];
returns?: JsDocReturnsTag;
}
export const TypeSystem = {
Flow: 'Flow',
TypeScript: 'TypeScript',
PropTypes: 'PropTypes',
Unknown: 'Unknown',
};
export type TypeSystemHandler = (propName: string, docgenInfo: DocgenInfo) => PropDef;
function createDefaultPropDef(propName: string, docgenInfo: DocgenInfo): PropDef {
const { description, required, defaultValue } = docgenInfo;
return {
name: propName,
type: null,
required,
description,
defaultValue: isNil(defaultValue) ? null : defaultValue.value,
};
}
export const propTypesHandler: TypeSystemHandler = (propName: string, docgenInfo: DocgenInfo) => {
const propDef = createDefaultPropDef(propName, docgenInfo);
propDef.type = docgenInfo.type;
if (!isNil(propDef.description)) {
if (propDef.description.includes('@')) {
const jsDocAst = parseComment(propDef.description);
// Always use the parsed description to ensure JSDoc is removed from the description.
if (!isNil(jsDocAst.description)) {
propDef.description = jsDocAst.description;
}
if (propDef.type.name === 'func') {
const tags = extractJsDocTags(jsDocAst);
const hasParams = tags.params.length > 0;
const hasReturnType = !isNil(tags.returns) && !isNil(tags.returns.type);
if (hasParams || hasReturnType) {
const funcParts = [];
if (hasParams) {
const funcParams = tags.params.map((x: any) => {
if (x.name && x.type) {
return `${x.name}: ${x.type}`;
}
if (x.name) {
return x.name;
}
return x.type;
});
funcParts.push(`(${funcParams.join(', ')})`);
} else {
funcParts.push('()');
}
if (hasReturnType) {
funcParts.push(`=> ${tags.returns.type}`);
}
propDef.type = {
name: funcParts.join(' '),
};
}
}
}
}
return propDef;
};
function extractJsDocTags(ast: JsDocAst): Record<string, any> {
const tags: ExtractedJsDocTags = {
params: [],
returns: null,
};
ast.tags.forEach(tag => {
// arg & argument are aliases for param.
if (tag.title === 'param' || tag.title === 'arg' || tag.title === 'argument') {
// When the @param doesn't have a name but have a type and a description, "null-null" is returned.
if (tag.name !== 'null-null') {
let paramName = tag.name;
if (paramName.includes('null')) {
// There is a few cases in which the returned param name contains "null".
// - @param {SyntheticEvent} event- Original SyntheticEvent
// - @param {SyntheticEvent} event.\n@returns {string}
paramName = paramName.replace('-null', '').replace('.null', '');
}
let paramType;
if (!isNil(tag.type)) {
const extractedTypeName = extractJsDocTypeName(tag.type);
if (!isNil(extractedTypeName)) {
paramType = extractedTypeName;
}
}
tags.params.push({
name: paramName,
type: paramType,
description: tag.description,
});
}
} else if (tag.title === 'returns') {
if (!isNil(tag.type)) {
tags.returns = {
type: extractJsDocTypeName(tag.type),
description: tag.description,
};
}
}
});
return tags;
}
function extractJsDocTypeName(type: any): string {
if (type.type === 'NameExpression') {
return type.name;
}
if (type.type === 'RecordType') {
const recordFields = type.fields.map((field: any) => {
if (!isNil(field.value)) {
const valueTypeName = extractJsDocTypeName(field.value);
return `${field.key}: ${valueTypeName}`;
}
return field.key;
});
return `({${recordFields.join(', ')}})`;
}
if (type.type === 'UnionType') {
const unionElements = type.elements.map(extractJsDocTypeName);
return `(${unionElements.join('|')})`;
}
// Only support untyped array: []. Might add more support later if required.
if (type.type === 'ArrayType') {
return '[]';
}
if (type.type === 'TypeApplication') {
if (!isNil(type.expression)) {
if (type.expression.name === 'Array') {
const arrayType = extractJsDocTypeName(type.applications[0]);
return `${arrayType}[]`;
}
}
}
if (
type.type === 'NullableType' ||
type.type === 'NonNullableType' ||
type.type === 'OptionalType'
) {
return extractJsDocTypeName(type.expression);
}
if (type.type === 'AllLiteral') {
return 'any';
}
return null;
}
export const tsHandler: TypeSystemHandler = (propName: string, docgenInfo: DocgenInfo) => {
const propDef = createDefaultPropDef(propName, docgenInfo);
propDef.type = docgenInfo.tsType;
return propDef;
};
export const flowHandler: TypeSystemHandler = (propName: string, docgenInfo: DocgenInfo) => {
const propDef = createDefaultPropDef(propName, docgenInfo);
propDef.type = docgenInfo.flowType;
return propDef;
};
export const unknownHandler: TypeSystemHandler = (propName: string, docgenInfo: DocgenInfo) => {
const propDef = createDefaultPropDef(propName, docgenInfo);
propDef.type = { name: 'unknown' };
return propDef;
};
export const TypeSystemHandlers: Record<string, TypeSystemHandler> = {
[TypeSystem.Flow]: flowHandler,
[TypeSystem.TypeScript]: tsHandler,
[TypeSystem.PropTypes]: propTypesHandler,
[TypeSystem.Unknown]: unknownHandler,
};
export const getPropTypeSystem = (docgenInfo: DocgenInfo): string => {
if (!isNil(docgenInfo.flowType)) {
return TypeSystem.Flow;
}
if (!isNil(docgenInfo.tsType)) {
return TypeSystem.TypeScript;
}
if (!isNil(docgenInfo.type)) {
return TypeSystem.PropTypes;
}
return TypeSystem.Unknown;
};
export const getTypeSystemHandler = (typeSystem: string): TypeSystemHandler => {
return TypeSystemHandlers[typeSystem];
};

View File

@ -2,7 +2,7 @@
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"types": ["webpack-env"]
"types": ["webpack-env", "jest"]
},
"include": ["src/**/*"],
"exclude": ["src/**.test.ts"]

View File

@ -1,3 +1,3 @@
import '@storybook/addon-actions/register';
import '@storybook/addon-options/register';
import '@storybook/addon-links/register';
import '@storybook/addon-a11y/register';

View File

@ -1,20 +0,0 @@
import { configure, addDecorator, addParameters } from '@storybook/react';
import { withInfo } from '@storybook/addon-info';
import { withA11y } from '@storybook/addon-a11y';
addDecorator(withA11y);
addParameters({
options: {
brandTitle: 'CRA TypeScript Kitchen Sink',
brandUrl: 'https://github.com/storybookjs/storybook/tree/master/examples/cra-ts-kitchen-sink',
},
});
addDecorator(withInfo());
function loadStories() {
// automatically import all story js files that end with *.stories.tsx
const req = require.context('../src', true, /\.stories\.tsx$/);
req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);

View File

@ -0,0 +1,13 @@
import { configure, addParameters, addDecorator } from '@storybook/react';
import { withA11y } from '@storybook/addon-a11y';
addDecorator(withA11y);
addParameters({
options: {
brandTitle: 'CRA TypeScript Kitchen Sink',
brandUrl: 'https://github.com/storybookjs/storybook/tree/master/examples/cra-ts-kitchen-sink',
},
});
// automatically import all files ending in *.stories.(tsx|jsx)
configure(require.context('../src/stories', true, /\.stories\.(mdx|[tj]sx?)$/), module);

View File

@ -0,0 +1,18 @@
const path = require('path');
module.exports = [
{
name: '@storybook/preset-create-react-app',
options: {
tsDocgenLoaderOptions: {
tsconfigPath: path.resolve(__dirname, '../tsconfig.json'),
},
},
},
{
name: '@storybook/addon-docs/react/preset',
options: {
sourceLoaderOptions: null,
},
},
];

View File

@ -1,10 +0,0 @@
const path = require('path');
module.exports = async ({ config }) => {
config.module.rules.push({
test: /\.tsx?$/,
include: path.resolve(__dirname, '../src'),
use: [require.resolve('react-docgen-typescript-loader')],
});
return config;
};

View File

@ -1,17 +0,0 @@
const config = require('../../jest.config');
module.exports = {
...config,
roots: [__dirname],
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/__mocks__/fileMock.js',
'\\.(css|scss)$': '<rootDir>/__mocks__/styleMock.js',
'\\.(md)$': '<rootDir>/__mocks__/htmlMock.js',
},
transform: {
...config.transform,
'^.+\\.svg$': '<rootDir>/node_modules/react-scripts/config/jest/fileTransform.js',
},
moduleDirectories: ['<rootDir>/node_modules', 'src'],
};

View File

@ -3,33 +3,46 @@
"version": "5.3.0-alpha.35",
"private": true,
"scripts": {
"build": "react-scripts build",
"build-storybook": "build-storybook -s public",
"eject": "react-scripts eject",
"lint": "tslint src/**/*.ts{,x}",
"storybook": "start-storybook -p 9010 -s public",
"test": "react-scripts test --env=jsdom"
"start": "react-scripts start",
"storybook": "start-storybook -p 9009 -s public",
"test": "react-scripts test"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"eslintConfig": {
"extends": "react-app"
},
"dependencies": {
"react": "^16.8.3",
"react-dom": "^16.8.3"
"@types/jest": "24.0.19",
"@types/node": "12.11.1",
"@types/react": "16.9.9",
"@types/react-dom": "16.9.2",
"react": "^16.10.2",
"react-dom": "^16.10.2",
"react-scripts": "3.2.0",
"typescript": "3.6.4"
},
"devDependencies": {
"@storybook/addon-a11y": "5.3.0-alpha.35",
"@storybook/addon-actions": "5.3.0-alpha.35",
"@storybook/addon-info": "5.3.0-alpha.35",
"@storybook/addon-options": "5.3.0-alpha.35",
"@storybook/addon-docs": "5.3.0-alpha.35",
"@storybook/addon-links": "5.3.0-alpha.35",
"@storybook/addons": "5.3.0-alpha.35",
"@storybook/react": "5.3.0-alpha.35",
"@types/enzyme": "^3.9.0",
"@types/react": "^16.8.14",
"@types/react-dom": "^16.8.2",
"enzyme": "^3.9.0",
"enzyme-adapter-react-16": "^1.9.1",
"enzyme-to-json": "^3.4.1",
"fork-ts-checker-webpack-plugin": "^3.0.1",
"react-docgen-typescript-loader": "^3.0.1",
"react-scripts": "^3.0.1",
"tslint": "^5.14.0",
"tslint-config-airbnb": "^5.11.1",
"typescript": "^3.4.0"
"@storybook/preset-create-react-app": "^1.2.0",
"@storybook/react": "5.3.0-alpha.35"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -2,12 +2,24 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="logo192.png" />
<!--
Notice the use of %PUBLIC_URL% in the tag above.
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
@ -15,14 +27,17 @@
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start`.
To create a production bundle, use `npm run build`.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@ -0,0 +1,22 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #09d3ac;
}

View File

@ -0,0 +1,26 @@
import React from 'react';
import logo from './logo.svg';
import './App.css';
const App: React.FC = () => {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;

View File

@ -1,12 +0,0 @@
import * as React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import Button from './Button';
storiesOf('Button', module).add(
'simple button',
() => <Button onClick={action('button clicked')}>OK</Button>,
{
info: { inline: true },
}
);

View File

@ -1,23 +0,0 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import Button from './Button';
describe('Button', () => {
it('renders', () => {
const wrapper = shallow(<Button>OK</Button>);
expect(wrapper).toMatchInlineSnapshot(`
<button
type="button"
>
OK
</button>
`);
});
it('calls onClick on button click', () => {
const handleClick = jest.fn();
const wrapper = shallow(<Button onClick={handleClick}>OK</Button>);
wrapper.find('button').simulate('click');
expect(handleClick).toHaveBeenCalled();
});
});

View File

@ -1,17 +0,0 @@
import React, { FunctionComponent } from 'react';
interface Props {
/**
* Click event handler
* @default null
*/
onClick?: () => void;
}
const Button: FunctionComponent<Props> = ({ children, onClick }) => (
<button type="button" onClick={onClick}>
{children}
</button>
);
export default Button;

View File

@ -0,0 +1,13 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

View File

@ -0,0 +1,12 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -0,0 +1,143 @@
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
type Config = {
onSuccess?: (registration: ServiceWorkerRegistration) => void;
onUpdate?: (registration: ServiceWorkerRegistration) => void;
};
export function register(config?: Config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(
(process as { env: { [key: string]: string } }).env.PUBLIC_URL,
window.location.href
);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl: string, config?: Config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl: string, config?: Config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}

View File

@ -1,4 +0,0 @@
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });

View File

@ -0,0 +1,14 @@
import React from 'react';
import { linkTo } from '@storybook/addon-links';
import { Welcome } from '@storybook/react/demo';
export default {
title: 'Welcome',
component: Welcome,
};
export const toStorybook = () => <Welcome showApp={linkTo('Button')} />;
toStorybook.story = {
name: 'to Storybook',
};

View File

@ -0,0 +1,20 @@
import React from "react";
import { action } from "@storybook/addon-actions";
import { Button } from "./Button";
export default {
title: "Button",
component: Button,
};
export const text = () => (
<Button onClick={action("clicked")}>Hello Button</Button>
);
export const emoji = () => (
<Button onClick={action("clicked")}>
<span role="img" aria-label="so cool">
😀 😎 👍 💯
</span>
</Button>
);

View File

@ -0,0 +1,17 @@
import React, { FC } from "react";
interface ButtonProps {
/**
* Simple click handler
*/
onClick?: () => void;
}
/**
* The world's most _basic_ button
*/
export const Button: FC<ButtonProps> = ({ children, onClick }) => (
<button onClick={onClick} type="button">
{children}
</button>
);

View File

@ -0,0 +1,18 @@
import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
import { Button } from './Button';
<Meta title="Test" />
Here's some _markdown_!
# Preview
<Preview>
<Story name="button">
<Button>hello</Button>
</Story>
</Preview>
# Props
<Props of={Button} />

View File

@ -0,0 +1,75 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
/**
* Button functional component
*/
export const ButtonFn = ({ onClick, children }) => <button onClick={onClick}>{children}</button>;
ButtonFn.propTypes = {
/**
* onClick description
*/
onClick: PropTypes.func
};
ButtonFn.defaultProps = {
onClick: null,
};
/**
* Button class React.Component
*/
export class ButtonReactComponent extends React.Component {
render() {
const { onClick, children } = this.props;
return <button onClick={onClick}>{children}</button>;
}
}
ButtonReactComponent.propTypes = {
/**
* onClick description
*/
onClick: PropTypes.func,
};
ButtonReactComponent.defaultProps = {
onClick: null,
};
/**
* Button class Component
*/
export class ButtonComponent extends Component {
render() {
const { onClick, children } = this.props;
return <button onClick={onClick}>{children}</button>;
}
}
ButtonComponent.propTypes = {
/**
* onClick description
*/
onClick: PropTypes.func,
};
ButtonComponent.defaultProps = {
onClick: null,
};
/**
* Button class static props
*/
export class ButtonStaticProps extends Component {
static propTypes = {
/**
* onClick description
*/
onClick: PropTypes.func,
};
static defaultProps = {
onClick: null,
};
render() {
const { onClick, children } = this.props;
return <button onClick={onClick}>{children}</button>;
}
}

View File

@ -0,0 +1,41 @@
import React, { FC, FunctionComponent, SyntheticEvent } from 'react';
interface ButtonProps {
/**
* onClick description
*/
onClick?: (e: SyntheticEvent) => void;
}
/**
* Button functional component (React.FC)
*/
export const ButtonReactFC: React.FC<ButtonProps> = ({ onClick, children }) => (
<button onClick={onClick}>{children}</button>
);
// @ts-ignore
ButtonReactFC.defaultProps = {
onClick: null,
};
/**
* Button functional component (FC)
*/
export const ButtonFC: FC<ButtonProps> = ({ onClick, children }) => (
<button onClick={onClick}>{children}</button>
);
// @ts-ignore
ButtonFC.defaultProps = {
onClick: null,
};
/**
* Button functional component (FunctionComponent)
*/
export const ButtonFunctionComponent: FunctionComponent<ButtonProps> = ({ onClick, children }) => (
<button onClick={onClick}>{children}</button>
);
// @ts-ignore
ButtonFunctionComponent.defaultProps = {
onClick: null,
};

View File

@ -0,0 +1,29 @@
import { Meta, Props, Description } from '@storybook/addon-docs/blocks';
import * as DocgenJS from './DocgenJS';
import * as DocgenTS from './DocgenTS';
<Meta title="Docgen|Props" />
export const DescriptionProps = ({ of }) => (
<>
<h2>{of.displayName}</h2>
<Description of={of} />
<Props of={of} />
</>
);
# React Docgen Test Cases
<div>
{Object.entries(DocgenJS).map(([key, val]) => (
<DescriptionProps key={key} of={val} />
))}
</div>
# React Typescript Docgen Test Cases
<div>
{Object.entries(DocgenTS).map(([key, val]) => (
<DescriptionProps key={key} of={val} />
))}
</div>

View File

@ -0,0 +1,465 @@
import React from 'react';
import PropTypes from 'prop-types';
export const ButtonTooManyProps = ({ onClick, children }) => <button onClick={onClick}>{children}</button>;
ButtonTooManyProps.propTypes = {
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick1: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick2: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick3: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick4: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick5: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick6: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick7: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick8: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick9: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick10: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick11: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick12: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick13: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick14: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick15: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick16: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick17: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick18: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick19: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick20: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick21: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick22: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick23: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick24: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick25: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick26: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick27: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick28: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick29: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick30: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick31: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick32: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick33: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick34: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick35: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick36: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick37: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick38: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick39: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick40: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick41: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick42: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick43: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick44: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick45: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick46: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick47: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick48: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick49: PropTypes.func,
/**
* onClick description
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {SyntheticEvent} event1 - React's original SyntheticEvent.
* @param {SyntheticEvent} event2 - React's original SyntheticEvent.
* @param {SyntheticEvent} event3 - React's original SyntheticEvent.
* @returns {void}
*/
onClick50: PropTypes.func
};

View File

@ -0,0 +1,10 @@
import { Meta, Props } from '@storybook/addon-docs/blocks';
import { ButtonTooManyProps } from "./jsdoc-perfo";
<Meta title="Docgen|Prop types/jsdoc-perfo" />
## Render 150 props with JSDoc tags
<Props of={ButtonTooManyProps} />
<Props of={ButtonTooManyProps} />
<Props of={ButtonTooManyProps} />

View File

@ -0,0 +1,232 @@
import React from 'react';
import PropTypes from 'prop-types';
export const JsDocProps = () => <div>JSDoc Props!</div>;
JsDocProps.propTypes = {
/**
* simple description.
*/
case1: PropTypes.string,
/**
* multi
* lines
* description
*/
case2: PropTypes.string,
/**
* *description* **with** `formatting`
*/
case3: PropTypes.string,
/**
* simple description and dummy JSDoc tag.
* @param event
*/
case4: PropTypes.string,
/**
* @param event
*/
case5: PropTypes.string,
/**
* simple description with a @.
*/
case6: PropTypes.string,
case7: PropTypes.func,
/**
* func with a simple description.
*/
case8: PropTypes.func,
/**
* @param event
*/
case9: PropTypes.func,
/**
* param with name
* @param event
*/
case10: PropTypes.func,
/**
* param with name & type
* @param {SyntheticEvent} event
*/
case11: PropTypes.func,
/**
* param with name, type & description
* @param {SyntheticEvent} event - React's original event
*/
case12: PropTypes.func,
/**
* param with type
* @param {SyntheticEvent}
*/
case13: PropTypes.func,
/**
* param with type & description
* @param {SyntheticEvent} - React's original event
*/
case14: PropTypes.func,
/**
* param with name & description
* @param event - React's original event
*/
case15: PropTypes.func,
/**
* autofix event-
* @param event- React's original event
*/
case16: PropTypes.func,
/**
* autofix event.
* @param event.
* @returns {string}
*/
case17: PropTypes.func,
/**
* with an empty param.
* @param
*/
case18: PropTypes.func,
/**
* with multiple empty params.
* @param
* @param
* @param
*/
case19: PropTypes.func,
/**
* with arg alias.
* @arg event
*/
case20: PropTypes.func,
/**
* with argument alias.
* @argument event
*/
case21: PropTypes.func,
/**
* with multiple params.
* @param {SyntheticEvent} event
* @param {string} stringValue
* @param {number} numberValue
*/
case22: PropTypes.func,
/**
* with an empty returns
* @returns
*/
case23: PropTypes.func,
/**
* with a returns with a type
* @returns {SyntheticEvent}
*/
case24: PropTypes.func,
/**
* with a returns with a type & description
* @returns {SyntheticEvent} - React's original event
*/
case25: PropTypes.func,
/**
* single param and a returns
* @param {string} stringValue
* @returns {SyntheticEvent} - React's original event
*/
case26: PropTypes.func,
/**
* multiple params and a returns
* @param {string} stringValue
* @param {number} numberValue
* @returns {SyntheticEvent} - React's original event
*/
case27: PropTypes.func,
/**
* multiple returns
* @returns {SyntheticEvent} - React's original event
* @returns {string} - Second returns
*/
case28: PropTypes.func,
/**
* param with unsupported JSDoc tags
* @param {SyntheticEvent} event - React's original event
* @type {number}
* @version 2
*/
case29: PropTypes.func,
/**
* param record type
* @param {{a: number, b: string}} myType
*/
case30: PropTypes.func,
/**
* param array type
* @param {string[]} myType
*/
case31: PropTypes.func,
/**
* param union type
* @param {(number|boolean)} myType
*/
case32: PropTypes.func,
/**
* param any type
* @param {*} myType
*/
case33: PropTypes.func,
/**
* param repeatable type
* @param {...number} myType
*/
case34: PropTypes.func,
/**
* optional param
* @param {number} [myType]
*/
case35: PropTypes.func,
/**
* optional param
* @param {number} [myType]
*/
case36: PropTypes.func,
/**
* dot in param name
* @param {number} my.type
*/
case37: PropTypes.func,
/**
* returns record type
* @returns {{a: number, b: string}}
*/
case38: PropTypes.func,
/**
* returns array type
* @returns {string[]}
*/
case39: PropTypes.func,
/**
* returns union type
* @returns {(number|boolean)}
*/
case40: PropTypes.func,
/**
* returns any type
* @returns {*}
*/
case41: PropTypes.func,
/**
* returns primitive
* @returns {string}
*/
case42: PropTypes.func,
/**
* returns void
* @returns {void}
*/
case43: PropTypes.func,
};
export const FailingJsDocProps = () => <div>Failing JSDoc Props!</div>;
FailingJsDocProps.propTypes = {
/**
* autofix event.
* @param event.
*/
case: PropTypes.func,
};

View File

@ -0,0 +1,7 @@
import { Meta, Props } from '@storybook/addon-docs/blocks';
import { JsDocProps, FailingJsDocProps } from "./jsdoc";
<Meta title="Docgen|Prop types/jsdoc" />
<Props of={JsDocProps} />
<Props of={FailingJsDocProps} />

View File

@ -1,8 +0,0 @@
export const addDecorator: any;
export const addParameters: any;
export const configure: any;
export const forceReRender: any;
export const getStorybook: any;
export const raw: any;
export const setAddon: any;
export const storiesOf: any;

View File

@ -1,25 +1,25 @@
{
"compilerOptions": {
"baseUrl": "src",
"paths": { "*": ["types/*"] },
"target": "es5",
"module": "esnext",
"lib" : ["esnext", "dom"],
"jsx": "preserve",
"moduleResolution": "node",
"esModuleInterop": true,
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": false,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true
"isolatedModules": true,
"noEmit": true,
"jsx": "react"
},
"include": [
"src"
],
"exclude": [
"src/setupTests.js"
]
}

View File

@ -97,6 +97,12 @@ export const PropRow: FC<PropRowProps> = ({
<PrettyPropType type={type} />
</StyledPropDef>
</td>
<td>{defaultValue === undefined ? '-' : <PrettyPropVal value={defaultValue} />}</td>
<td>
{defaultValue === null || defaultValue === undefined ? (
'-'
) : (
<PrettyPropVal value={defaultValue} />
)}
</td>
</tr>
);

View File

@ -138,6 +138,8 @@
"@storybook/eslint-config-storybook": "^2.0.0",
"@storybook/linter-config": "^2.0.0",
"@testing-library/react": "^9.2.0",
"@types/doctrine": "^0.0.3",
"@types/enzyme": "^3.10.3",
"@types/jest": "^24.0.11",
"@types/lodash": "^4.14.129",
"@types/node": "^12.7.9",

194
yarn.lock
View File

@ -2080,25 +2080,6 @@
webpack-dev-server "3.2.0"
xmldom "0.1.27"
"@fimbul/bifrost@^0.21.0":
version "0.21.0"
resolved "https://registry.yarnpkg.com/@fimbul/bifrost/-/bifrost-0.21.0.tgz#d0fafa25938fda475657a6a1e407a21bbe02c74e"
integrity sha512-ou8VU+nTmOW1jeg+FT+sn+an/M0Xb9G16RucrfhjXGWv1Q97kCoM5CG9Qj7GYOSdu7km72k7nY83Eyr53Bkakg==
dependencies:
"@fimbul/ymir" "^0.21.0"
get-caller-file "^2.0.0"
tslib "^1.8.1"
tsutils "^3.5.0"
"@fimbul/ymir@^0.21.0":
version "0.21.0"
resolved "https://registry.yarnpkg.com/@fimbul/ymir/-/ymir-0.21.0.tgz#8525726787aceeafd4e199472c0d795160b5d4a1"
integrity sha512-T/y7WqPsm4n3zhT08EpB5sfdm2Kvw3gurAxr2Lr5dQeLi8ZsMlNT/Jby+ZmuuAAd1PnXYzKp+2SXgIkQIIMCUg==
dependencies:
inversify "^5.0.0"
reflect-metadata "^0.1.12"
tslib "^1.8.1"
"@glimmer/di@^0.2.0":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.2.1.tgz#5286b6b32040232b751138f6d006130c728d4b3d"
@ -3382,6 +3363,25 @@
remark-lint "^6.0.4"
remark-preset-lint-recommended "^3.0.2"
"@storybook/node-logger@^5.2.4":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-5.2.5.tgz#87f53de795db6eed912b54d3cca82fd7b7857771"
integrity sha512-UNyXGOhOr4Bn9wKwBTZABTBXQzrgvGxPLSmvAFZuMx9ZhqoT/EXAuLUl0/wiJtkyuYpoOOskNwIdKxLBdTKS2w==
dependencies:
chalk "^2.4.2"
core-js "^3.0.1"
npmlog "^4.1.2"
pretty-hrtime "^1.0.3"
regenerator-runtime "^0.12.1"
"@storybook/preset-create-react-app@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@storybook/preset-create-react-app/-/preset-create-react-app-1.2.0.tgz#081fe3d66a97721d9e82e6cf198f0f9d57bc489c"
integrity sha512-SvfHsEJ0wA+9goJOci2P2CvI0K9AQEOuPzdB092ts21PIxOj2KQUiTdR/UjodNUcKguHZzPeMOjJr23EFLf4qA==
dependencies:
"@storybook/node-logger" "^5.2.4"
react-docgen-typescript-loader "^3.3.0"
"@svgr/babel-plugin-add-jsx-attribute@^4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz#dadcb6218503532d6884b210e7f3c502caaa44b1"
@ -3628,7 +3628,12 @@
resolved "https://registry.yarnpkg.com/@types/core-js/-/core-js-2.5.2.tgz#d4c25420044d4a5b65e00a82fc04b7824b62691f"
integrity sha512-+NPqjXgyA02xTHKJDeDca9u8Zr42ts6jhdND4C3PrPeQ35RJa0dmfAedXW7a9K4N1QcBbuWI1nSfGK4r1eVFCQ==
"@types/enzyme@^3.9.0":
"@types/doctrine@^0.0.3":
version "0.0.3"
resolved "https://registry.yarnpkg.com/@types/doctrine/-/doctrine-0.0.3.tgz#e892d293c92c9c1d3f9af72c15a554fbc7e0895a"
integrity sha1-6JLSk8ksnB0/mvcsFaVU+8fgiVo=
"@types/enzyme@^3.10.3":
version "3.10.3"
resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.10.3.tgz#02b6c5ac7d0472005944a652e79045e2f6c66804"
integrity sha512-f/Kcb84sZOSZiBPCkr4He9/cpuSLcKRyQaEE20Q30Prx0Dn6wcyMAWI0yofL6yvd9Ht9G7EVkQeRqK0n5w8ILw==
@ -3739,6 +3744,13 @@
dependencies:
"@types/jest-diff" "*"
"@types/jest@24.0.19":
version "24.0.19"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.19.tgz#f7036058d2a5844fe922609187c0ad8be430aff5"
integrity sha512-YYiqfSjocv7lk5H/T+v5MjATYjaTMsUkbDnjGqSMoO88jWdtJXJV4ST/7DKZcoMHMBvB2SeSfyOzZfkxXHR5xg==
dependencies:
"@types/jest-diff" "*"
"@types/jest@^23.0.2", "@types/jest@^23.3.1":
version "23.3.14"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-23.3.14.tgz#37daaf78069e7948520474c87b80092ea912520a"
@ -3793,6 +3805,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a"
integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==
"@types/node@12.11.1":
version "12.11.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.1.tgz#1fd7b821f798b7fa29f667a1be8f3442bb8922a3"
integrity sha512-TJtwsqZ39pqcljJpajeoofYRfeZ7/I/OMUQ5pR4q5wOKf2ocrUvBAZUMhWsOvKx3dVc/aaV5GluBivt0sWqA5A==
"@types/node@^6.0.0":
version "6.14.8"
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.14.8.tgz#faf07db8ccc3dec8cb4d301869c1ad872b9663a1"
@ -3874,13 +3891,20 @@
dependencies:
"@types/react" "*"
"@types/react-dom@*", "@types/react-dom@^16.8.2":
"@types/react-dom@*":
version "16.9.3"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.3.tgz#4006ff0e13958af91313869077c04cb20d9b9d04"
integrity sha512-FUuZKXPr9qlzUT9lhuzrZgLjH63TvNn28Ch3MvKG4B+F52zQtO8DtE0Opbncy3xaucNZM2WIPfuNTgkbKx5Brg==
dependencies:
"@types/react" "*"
"@types/react-dom@16.9.2":
version "16.9.2"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.2.tgz#90f9e6c161850be1feb31d2f448121be2a4f3b47"
integrity sha512-hgPbBoI1aTSTvZwo8HYw35UaTldW6n2ETLvHAcfcg1FaOuBV3olmyCe5eMpx2WybWMBPv0MdU2t5GOcQhP+3zA==
dependencies:
"@types/react" "*"
"@types/react-lifecycles-compat@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/react-lifecycles-compat/-/react-lifecycles-compat-3.0.1.tgz#a0b1fe18cfb9435bd52737829a69cbe93faf32e2"
@ -3944,6 +3968,14 @@
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/react@16.9.9":
version "16.9.9"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.9.tgz#a62c6f40f04bc7681be5e20975503a64fe783c3a"
integrity sha512-L+AudFJkDukk+ukInYvpoAPyJK5q1GanFOINOJnM0w6tUgITuWvJ4jyoBPFL7z4/L8hGLd+K/6xR5uUjXu0vVg==
dependencies:
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/selenium-webdriver@^3.0.0":
version "3.0.16"
resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz#50a4755f8e33edacd9c406729e9b930d2451902a"
@ -7950,11 +7982,6 @@ buffer@^5.0.2, buffer@^5.1.0:
base64-js "^1.0.2"
ieee754 "^1.1.4"
builtin-modules@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
builtin-status-codes@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
@ -9000,7 +9027,7 @@ commander@2.8.x:
dependencies:
graceful-readlink ">= 1.0.0"
commander@^2.11.0, commander@^2.12.1, commander@^2.15.1, commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@^2.6.0, commander@^2.8.1, commander@^2.9.0, commander@~2.20.3:
commander@^2.11.0, commander@^2.15.1, commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@^2.6.0, commander@^2.8.1, commander@^2.9.0, commander@~2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@ -10649,14 +10676,6 @@ dns-txt@^2.0.2:
dependencies:
buffer-indexof "^1.0.0"
doctrine@0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523"
integrity sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=
dependencies:
esutils "^1.1.6"
isarray "0.0.1"
doctrine@1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
@ -12195,11 +12214,6 @@ estree-walker@^0.6.1:
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==
esutils@^1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-1.1.6.tgz#c01ccaa9ae4b897c6d0c3e210ae52f3c7a844375"
integrity sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=
esutils@^2.0.0, esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
@ -14055,7 +14069,7 @@ get-caller-file@^1.0.1:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
get-caller-file@^2.0.0, get-caller-file@^2.0.1, get-caller-file@^2.0.5:
get-caller-file@^2.0.1, get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
@ -15909,11 +15923,6 @@ invariant@2.2.4, invariant@^2.2.1, invariant@^2.2.2, invariant@^2.2.3, invariant
dependencies:
loose-envify "^1.0.0"
inversify@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/inversify/-/inversify-5.0.1.tgz#500d709b1434896ce5a0d58915c4a4210e34fb6e"
integrity sha512-Ieh06s48WnEYGcqHepdsJUIJUXpwH5o5vodAX+DK2JA/gjy4EbEcQZxw+uFfzysmKjiLXGYwNG3qDZsKVMcINQ==
invert-kv@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
@ -24629,7 +24638,7 @@ react-devtools-core@^3.4.2, react-devtools-core@^3.6.0:
shell-quote "^1.6.1"
ws "^3.3.1"
react-docgen-typescript-loader@^3.0.1:
react-docgen-typescript-loader@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/react-docgen-typescript-loader/-/react-docgen-typescript-loader-3.3.0.tgz#c1f5c1db9a2b6a6bca220bc50fee0a071bc75499"
integrity sha512-gC0TeWTz7s7OMyeABppQGbbrtSNi0yl/gBgZJElBtaBFNSJlHH1sfgQybHZmlZqFcn4UBa+8DOGT6wEJKWTV6g==
@ -24667,7 +24676,7 @@ react-dom@^15.4.2:
object-assign "^4.1.0"
prop-types "^15.5.10"
react-dom@^16.8.3, react-dom@^16.8.4:
react-dom@^16.10.2, react-dom@^16.8.3, react-dom@^16.8.4:
version "16.11.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.11.0.tgz#7e7c4a5a85a569d565c2462f5d345da2dd849af5"
integrity sha512-nrRyIUE1e7j8PaXSPtyRKtz+2y9ubW/ghNgqKFHHAHaeP0fpF5uXR+sq8IMRHC+ZUxw7W9NyCDTBtwWxvkb0iA==
@ -25112,7 +25121,7 @@ react-scripts@3.0.1:
optionalDependencies:
fsevents "2.0.6"
react-scripts@^3.0.1:
react-scripts@3.2.0, react-scripts@^3.0.1:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.2.0.tgz#58ccd6b4ffa27f1b4d2986cbdcaa916660e9e33c"
integrity sha512-6LzuKbE2B4eFQG6i1FnTScn9HDcWBfXXnOwW9xKFPJ/E3rK8i1ufbOZ0ocKyRPxJAKdN7iqg3i7lt0+oxkSVOA==
@ -25259,7 +25268,7 @@ react-transition-group@^2.2.1:
prop-types "^15.6.2"
react-lifecycles-compat "^3.0.4"
react@*, react@^16.6.0, react@^16.8.3, react@^16.8.4:
react@*, react@^16.10.2, react@^16.6.0, react@^16.8.3, react@^16.8.4:
version "16.11.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.11.0.tgz#d294545fe62299ccee83363599bf904e4a07fdbb"
integrity sha512-M5Y8yITaLmU0ynd0r1Yvfq98Rmll6q8AxaEe88c8e7LxO8fZ2cNgmFt0aGAS9wzf1Ao32NKXtCl+/tVVtkxq6g==
@ -25644,7 +25653,7 @@ redux@^4.0.0, redux@^4.0.1:
loose-envify "^1.4.0"
symbol-observable "^1.2.0"
reflect-metadata@^0.1.12, reflect-metadata@^0.1.2:
reflect-metadata@^0.1.2:
version "0.1.13"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
@ -25690,6 +25699,11 @@ regenerator-runtime@^0.11.0:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
regenerator-runtime@^0.12.1:
version "0.12.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
regenerator-transform@^0.10.0:
version "0.10.1"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd"
@ -29502,84 +29516,12 @@ tsconfig-paths@^3.4.0:
minimist "^1.2.0"
strip-bom "^3.0.0"
tslib@1.10.0, tslib@^1.7.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
tslib@1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
version "1.10.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
tslib@1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8"
integrity sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==
tslint-config-airbnb@^5.11.1:
version "5.11.2"
resolved "https://registry.yarnpkg.com/tslint-config-airbnb/-/tslint-config-airbnb-5.11.2.tgz#2f3d239fa3923be8e7a4372217a7ed552671528f"
integrity sha512-mUpHPTeeCFx8XARGG/kzYP4dPSOgoCqNiYbGHh09qTH8q+Y1ghsOgaeZKYYQT7IyxMos523z/QBaiv2zKNBcow==
dependencies:
tslint-consistent-codestyle "^1.14.1"
tslint-eslint-rules "^5.4.0"
tslint-microsoft-contrib "~5.2.1"
tslint-consistent-codestyle@^1.14.1:
version "1.16.0"
resolved "https://registry.yarnpkg.com/tslint-consistent-codestyle/-/tslint-consistent-codestyle-1.16.0.tgz#52348ea899a7e025b37cc6545751c6a566a19077"
integrity sha512-ebR/xHyMEuU36hGNOgCfjGBNYxBPixf0yU1Yoo6s3BrpBRFccjPOmIVaVvQsWAUAMdmfzHOCihVkcaMfimqvHw==
dependencies:
"@fimbul/bifrost" "^0.21.0"
tslib "^1.7.1"
tsutils "^2.29.0"
tslint-eslint-rules@^5.4.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/tslint-eslint-rules/-/tslint-eslint-rules-5.4.0.tgz#e488cc9181bf193fe5cd7bfca213a7695f1737b5"
integrity sha512-WlSXE+J2vY/VPgIcqQuijMQiel+UtmXS+4nvK4ZzlDiqBfXse8FAvkNnTcYhnQyOTW5KFM+uRRGXxYhFpuBc6w==
dependencies:
doctrine "0.7.2"
tslib "1.9.0"
tsutils "^3.0.0"
tslint-microsoft-contrib@~5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/tslint-microsoft-contrib/-/tslint-microsoft-contrib-5.2.1.tgz#a6286839f800e2591d041ea2800c77487844ad81"
integrity sha512-PDYjvpo0gN9IfMULwKk0KpVOPMhU6cNoT9VwCOLeDl/QS8v8W2yspRpFFuUS7/c5EIH/n8ApMi8TxJAz1tfFUA==
dependencies:
tsutils "^2.27.2 <2.29.0"
tslint@^5.14.0:
version "5.20.0"
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.0.tgz#fac93bfa79568a5a24e7be9cdde5e02b02d00ec1"
integrity sha512-2vqIvkMHbnx8acMogAERQ/IuINOq6DFqgF8/VDvhEkBqQh/x6SP0Y+OHnKth9/ZcHQSroOZwUQSN18v8KKF0/g==
dependencies:
"@babel/code-frame" "^7.0.0"
builtin-modules "^1.1.1"
chalk "^2.3.0"
commander "^2.12.1"
diff "^4.0.1"
glob "^7.1.1"
js-yaml "^3.13.1"
minimatch "^3.0.4"
mkdirp "^0.5.1"
resolve "^1.3.2"
semver "^5.3.0"
tslib "^1.8.0"
tsutils "^2.29.0"
"tsutils@^2.27.2 <2.29.0":
version "2.28.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.28.0.tgz#6bd71e160828f9d019b6f4e844742228f85169a1"
integrity sha512-bh5nAtW0tuhvOJnx1GLRn5ScraRLICGyJV5wJhtRWOLsxW70Kk5tZtpK3O/hW6LDnqKS9mlUMPZj9fEMJ0gxqA==
dependencies:
tslib "^1.8.1"
tsutils@^2.29.0:
version "2.29.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==
dependencies:
tslib "^1.8.1"
tsutils@^3.0.0, tsutils@^3.17.1, tsutils@^3.5.0, tsutils@^3.7.0:
tsutils@^3.17.1, tsutils@^3.7.0:
version "3.17.1"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==
@ -29678,7 +29620,7 @@ typescript@3.5.3:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
typescript@^3.2.2, typescript@^3.4.0:
typescript@3.6.4, typescript@^3.2.2, typescript@^3.4.0:
version "3.6.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.4.tgz#b18752bb3792bc1a0281335f7f6ebf1bbfc5b91d"
integrity sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==