diff --git a/index.d.ts b/index.d.ts index ad14d0699d..27f48ae99f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -64,7 +64,7 @@ export { default as Flag, FlagProps } from './dist/commonjs/elements/Flag' export { default as Header, HeaderProps } from './dist/commonjs/elements/Header' export { default as HeaderContent, HeaderContentProps } from './dist/commonjs/elements/Header/HeaderContent' -export { default as HeaderSubheader, HeaderSubHeaderProps } from './dist/commonjs/elements/Header/HeaderSubheader' +export { default as HeaderSubheader, HeaderSubheaderProps } from './dist/commonjs/elements/Header/HeaderSubheader' export { default as Icon, IconProps } from './dist/commonjs/elements/Icon' export { default as IconGroup, IconGroupProps } from './dist/commonjs/elements/Icon/IconGroup' diff --git a/src/collections/Breadcrumb/BreadcrumbSection.d.ts b/src/collections/Breadcrumb/BreadcrumbSection.d.ts index 995482732d..f6c4558aaa 100644 --- a/src/collections/Breadcrumb/BreadcrumbSection.d.ts +++ b/src/collections/Breadcrumb/BreadcrumbSection.d.ts @@ -15,6 +15,9 @@ export interface BreadcrumbSectionProps { /** Additional classes. */ className?: string; + /** Shorthand for primary content. */ + content?: any; + /** Render as an `a` tag instead of a `div` and adds the href attribute. */ href?: string; diff --git a/src/collections/Form/FormButton.d.ts b/src/collections/Form/FormButton.d.ts index cc624d49aa..fc5152b848 100644 --- a/src/collections/Form/FormButton.d.ts +++ b/src/collections/Form/FormButton.d.ts @@ -4,6 +4,13 @@ import { ButtonProps } from '../../elements/Button'; import { FormFieldProps } from './FormField'; export interface FormButtonProps extends FormFieldProps, ButtonProps { + [key: string]: any; + + /** An element type to render as (string or function). */ + as?: any; + + /** A FormField control prop. */ + control?: any; } declare const FormButton: React.StatelessComponent; diff --git a/src/collections/Form/FormCheckbox.d.ts b/src/collections/Form/FormCheckbox.d.ts index 479f31b2c5..453467878b 100644 --- a/src/collections/Form/FormCheckbox.d.ts +++ b/src/collections/Form/FormCheckbox.d.ts @@ -4,7 +4,13 @@ import { CheckboxProps } from '../../modules/Checkbox'; import { FormFieldProps } from './FormField'; export interface FormCheckboxProps extends FormFieldProps, CheckboxProps { - type?: 'checkbox' | 'radio'; + [key: string]: any; + + /** An element type to render as (string or function). */ + as?: any; + + /** A FormField control prop. */ + control?: any; } declare const FormCheckbox: React.StatelessComponent; diff --git a/src/collections/Form/FormDropdown.d.ts b/src/collections/Form/FormDropdown.d.ts index 6a51c3c8c3..50d97226c1 100644 --- a/src/collections/Form/FormDropdown.d.ts +++ b/src/collections/Form/FormDropdown.d.ts @@ -4,6 +4,13 @@ import { DropdownProps } from '../../modules/Dropdown'; import { FormFieldProps } from './FormField'; export interface FormDropdownProps extends FormFieldProps, DropdownProps { + [key: string]: any; + + /** An element type to render as (string or function). */ + as?: any; + + /** A FormField control prop. */ + control?: any; } declare const FormDropdown: React.StatelessComponent; diff --git a/src/collections/Form/FormInput.d.ts b/src/collections/Form/FormInput.d.ts index fa001ba623..fbc2664302 100644 --- a/src/collections/Form/FormInput.d.ts +++ b/src/collections/Form/FormInput.d.ts @@ -4,6 +4,13 @@ import { InputProps } from '../../elements/Input'; import { FormFieldProps } from './FormField'; export interface FormInputProps extends FormFieldProps, InputProps { + [key: string]: any; + + /** An element type to render as (string or function). */ + as?: any; + + /** A FormField control prop. */ + control?: any; } declare const FormInput: React.StatelessComponent; diff --git a/src/collections/Form/FormRadio.d.ts b/src/collections/Form/FormRadio.d.ts index a79d6c8ae9..4f95ab812d 100644 --- a/src/collections/Form/FormRadio.d.ts +++ b/src/collections/Form/FormRadio.d.ts @@ -4,7 +4,13 @@ import { RadioProps } from '../../addons/Radio'; import { FormFieldProps } from './FormField'; export interface FormRadioProps extends FormFieldProps, RadioProps { - type?: 'checkbox' | 'radio'; + [key: string]: any; + + /** An element type to render as (string or function). */ + as?: any; + + /** A FormField control prop. */ + control?: any; } declare const FormRadio: React.StatelessComponent; diff --git a/src/collections/Form/FormSelect.d.ts b/src/collections/Form/FormSelect.d.ts index 55230ae476..d889c56644 100644 --- a/src/collections/Form/FormSelect.d.ts +++ b/src/collections/Form/FormSelect.d.ts @@ -4,6 +4,13 @@ import { SelectProps } from '../../addons/Select'; import { FormFieldProps } from './FormField'; export interface FormSelectProps extends FormFieldProps, SelectProps { + [key: string]: any; + + /** An element type to render as (string or function). */ + as?: any; + + /** A FormField control prop. */ + control?: any; } declare const FormSelect: React.StatelessComponent; diff --git a/src/collections/Form/FormTextArea.d.ts b/src/collections/Form/FormTextArea.d.ts index 9c9f4c4ea6..a390c5d42c 100644 --- a/src/collections/Form/FormTextArea.d.ts +++ b/src/collections/Form/FormTextArea.d.ts @@ -4,6 +4,13 @@ import { TextAreaProps } from '../../addons/TextArea'; import { FormFieldProps } from './FormField'; export interface FormTextAreaProps extends FormFieldProps, TextAreaProps { + [key: string]: any; + + /** An element type to render as (string or function). */ + as?: any; + + /** A FormField control prop. */ + control?: any; } declare const FormTextArea: React.StatelessComponent; diff --git a/src/collections/Message/Message.js b/src/collections/Message/Message.js index a30635b396..b650eca9f3 100644 --- a/src/collections/Message/Message.js +++ b/src/collections/Message/Message.js @@ -88,12 +88,12 @@ export default class Message extends Component { /** A message may be formatted to display a positive message. Same as `success`. */ positive: PropTypes.bool, - /** A message may be formatted to display a positive message. Same as `positive`. */ - success: PropTypes.bool, - /** A message can have different sizes. */ size: PropTypes.oneOf(_.without(SUI.SIZES, 'medium')), + /** A message may be formatted to display a positive message. Same as `positive`. */ + success: PropTypes.bool, + /** A message can be set to visible to force itself to be shown. */ visible: PropTypes.bool, diff --git a/src/collections/Table/TableHeaderCell.d.ts b/src/collections/Table/TableHeaderCell.d.ts index 3c9d090e73..4f3431fc54 100644 --- a/src/collections/Table/TableHeaderCell.d.ts +++ b/src/collections/Table/TableHeaderCell.d.ts @@ -2,6 +2,15 @@ import * as React from 'react'; import { TableCellProps } from './TableCell'; export interface TableHeaderCellProps extends TableCellProps { + [key: string]: any; + + /** An element type to render as (string or function). */ + as?: any; + + /** Additional classes. */ + className?: string; + + /** A header cell can be sorted in ascending or descending order. */ sorted?: 'ascending' | 'descending'; } diff --git a/src/elements/Button/Button.js b/src/elements/Button/Button.js index 29775b0f53..40230adc5b 100644 --- a/src/elements/Button/Button.js +++ b/src/elements/Button/Button.js @@ -65,12 +65,12 @@ class Button extends Component { ), ]), - /** Additional classes. */ - className: PropTypes.string, - /** A button can be circular. */ circular: PropTypes.bool, + /** Additional classes. */ + className: PropTypes.string, + /** A button can have different colors */ color: PropTypes.oneOf([ ...SUI.COLORS, diff --git a/src/elements/Header/HeaderSubheader.d.ts b/src/elements/Header/HeaderSubheader.d.ts index 5093326e5b..42dd959c91 100644 --- a/src/elements/Header/HeaderSubheader.d.ts +++ b/src/elements/Header/HeaderSubheader.d.ts @@ -1,6 +1,6 @@ import * as React from 'react'; -export interface HeaderSubHeaderProps { +export interface HeaderSubheaderProps { [key: string]: any; /** An element type to render as (string or function). */ @@ -16,6 +16,6 @@ export interface HeaderSubHeaderProps { content?: React.ReactNode; } -declare const HeaderSubHeader: React.StatelessComponent; +declare const HeaderSubHeader: React.StatelessComponent; export default HeaderSubHeader; diff --git a/src/elements/Image/Image.d.ts b/src/elements/Image/Image.d.ts index e4e2ee4378..76db307bdf 100644 --- a/src/elements/Image/Image.d.ts +++ b/src/elements/Image/Image.d.ts @@ -12,12 +12,12 @@ import ImageGroup from './ImageGroup'; export interface ImageProps { [key: string]: any; - /** Alternate text for the image specified. */ - alt?: string; - /** An element type to render as (string or function). */ as?: any; + /** Alternate text for the image specified. */ + alt?: string; + /** An image may be formatted to appear inline with text as an avatar. */ avatar?: boolean; @@ -27,6 +27,9 @@ export interface ImageProps { /** An image can appear centered in a content block. */ centered?: boolean; + /** Primary content. */ + children?: React.ReactNode; + /** Additional classes. */ className?: string; @@ -43,7 +46,10 @@ export interface ImageProps { fluid?: boolean; /** The img element height attribute. */ - height?: string|number; + height?: string | number; + + /** An image can be hidden. */ + hidden?: boolean; /** Renders the Image as an tag with this href. */ href?: string; diff --git a/src/elements/Image/Image.js b/src/elements/Image/Image.js index dc49db0bff..857305b537 100644 --- a/src/elements/Image/Image.js +++ b/src/elements/Image/Image.js @@ -137,8 +137,8 @@ Image.propTypes = { /** The img element height attribute. */ height: PropTypes.oneOfType([ - PropTypes.string, PropTypes.number, + PropTypes.string, ]), /** An image can be hidden. */ diff --git a/src/elements/Label/LabelGroup.d.ts b/src/elements/Label/LabelGroup.d.ts index b499e36a40..81af4f17b9 100644 --- a/src/elements/Label/LabelGroup.d.ts +++ b/src/elements/Label/LabelGroup.d.ts @@ -11,7 +11,7 @@ export interface LabelGroupProps { children?: React.ReactNode; /** Labels can share shapes. */ - circular: boolean; + circular?: boolean; /** Additional classes. */ className?: string; diff --git a/src/elements/List/ListIcon.d.ts b/src/elements/List/ListIcon.d.ts index 3fe5293c59..12795bbf0b 100644 --- a/src/elements/List/ListIcon.d.ts +++ b/src/elements/List/ListIcon.d.ts @@ -4,6 +4,10 @@ import { SemanticVERTICALALIGNMENTS } from '../..'; import { IconProps } from '../Icon'; export interface ListIconProps extends IconProps { + /** Additional classes. */ + className?: string; + + /** An element inside a list can be vertically aligned. */ verticalAlign?: SemanticVERTICALALIGNMENTS; } diff --git a/src/elements/Reveal/Reveal.d.ts b/src/elements/Reveal/Reveal.d.ts index 5c2bf8fadb..df120c0b9c 100644 --- a/src/elements/Reveal/Reveal.d.ts +++ b/src/elements/Reveal/Reveal.d.ts @@ -15,12 +15,12 @@ export interface RevealProps { | 'move' | 'move right' | 'move up' | 'move down' | 'rotate' | 'rotate left'; - /** Additional classes. */ - className?: string; - /** Primary content. */ children?: React.ReactNode; + /** Additional classes. */ + className?: string; + /** A disabled reveal will not animate when hovered. */ disabled?: boolean; diff --git a/src/elements/Step/StepContent.js b/src/elements/Step/StepContent.js index b521b5fd99..4458e9dfea 100644 --- a/src/elements/Step/StepContent.js +++ b/src/elements/Step/StepContent.js @@ -44,12 +44,12 @@ StepContent.propTypes = { /** An element type to render as (string or function). */ as: customPropTypes.as, - /** Additional classes. */ - className: PropTypes.string, - /** Primary content. */ children: PropTypes.node, + /** Additional classes. */ + className: PropTypes.string, + /** Shorthand for StepDescription. */ description: customPropTypes.itemShorthand, diff --git a/src/elements/Step/StepDescription.js b/src/elements/Step/StepDescription.js index af48c30044..55c53bd2d2 100644 --- a/src/elements/Step/StepDescription.js +++ b/src/elements/Step/StepDescription.js @@ -33,12 +33,12 @@ StepDescription.propTypes = { /** An element type to render as (string or function). */ as: customPropTypes.as, - /** Additional classes. */ - className: PropTypes.string, - /** Primary content. */ children: PropTypes.node, + /** Additional classes. */ + className: PropTypes.string, + /** Shorthand for primary content. */ description: customPropTypes.contentShorthand, } diff --git a/src/elements/Step/StepTitle.js b/src/elements/Step/StepTitle.js index bfb5061ed7..b63703991e 100644 --- a/src/elements/Step/StepTitle.js +++ b/src/elements/Step/StepTitle.js @@ -36,12 +36,12 @@ StepTitle.propTypes = { /** An element type to render as (string or function). */ as: customPropTypes.as, - /** Additional classes. */ - className: PropTypes.string, - /** Primary content. */ children: PropTypes.node, + /** Additional classes. */ + className: PropTypes.string, + /** Shorthand for primary content. */ title: customPropTypes.contentShorthand, } diff --git a/src/modules/Accordion/AccordionContent.d.ts b/src/modules/Accordion/AccordionContent.d.ts index f331aa013b..32b5cf5c74 100644 --- a/src/modules/Accordion/AccordionContent.d.ts +++ b/src/modules/Accordion/AccordionContent.d.ts @@ -14,6 +14,9 @@ export interface AccordionContentProps { /** Additional classes. */ className?: string; + + /** Shorthand for primary content. */ + content?: any; } declare const AccordionContent: React.StatelessComponent; diff --git a/src/modules/Accordion/AccordionTitle.d.ts b/src/modules/Accordion/AccordionTitle.d.ts index 15bd83ad3c..da0d9b58d6 100644 --- a/src/modules/Accordion/AccordionTitle.d.ts +++ b/src/modules/Accordion/AccordionTitle.d.ts @@ -3,18 +3,21 @@ import * as React from 'react'; export interface AccordionTitleProps { [key: string]: any; - /** Whether or not the title is in the open state. */ - active?: boolean; - /** An element type to render as (string or function). */ as?: any; + /** Whether or not the title is in the open state. */ + active?: boolean; + /** Primary content. */ children?: React.ReactNode; /** Additional classes. */ className?: string; + /** Shorthand for primary content. */ + content?: any; + /** * Called on click. * diff --git a/src/modules/Checkbox/Checkbox.d.ts b/src/modules/Checkbox/Checkbox.d.ts index 37629a85a1..ab2eecb198 100644 --- a/src/modules/Checkbox/Checkbox.d.ts +++ b/src/modules/Checkbox/Checkbox.d.ts @@ -67,6 +67,9 @@ export interface CheckboxProps { /** Format to emphasize the current selection state. */ slider?: boolean; + /** A checkbox can receive focus. */ + tabIndex?: number | string; + /** Format to show an on or off choice. */ toggle?: boolean; diff --git a/src/modules/Checkbox/Checkbox.js b/src/modules/Checkbox/Checkbox.js index ab99e4e51a..991cde4435 100644 --- a/src/modules/Checkbox/Checkbox.js +++ b/src/modules/Checkbox/Checkbox.js @@ -91,6 +91,12 @@ export default class Checkbox extends Component { customPropTypes.disallow(['radio', 'toggle']), ]), + /** A checkbox can receive focus. */ + tabIndex: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.string, + ]), + /** Format to show an on or off choice. */ toggle: customPropTypes.every([ PropTypes.bool, @@ -102,12 +108,6 @@ export default class Checkbox extends Component { /** The HTML input value. */ value: PropTypes.string, - - /** A checkbox can receive focus. */ - tabIndex: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.string, - ]), } static defaultProps = { diff --git a/src/modules/Dropdown/Dropdown.d.ts b/src/modules/Dropdown/Dropdown.d.ts index 2370ffd3cf..45a998cef3 100644 --- a/src/modules/Dropdown/Dropdown.d.ts +++ b/src/modules/Dropdown/Dropdown.d.ts @@ -215,6 +215,9 @@ export interface DropdownProps { /** Define whether the highlighted item should be selected on blur. */ selectOnBlur?: boolean; + /** Currently selected label in multi-select. */ + selectedLabel?: number | string; + /** A dropdown can be used to select between choices in a form. */ selection?: any; @@ -234,7 +237,7 @@ export interface DropdownProps { value?: number | string | Array; /** A dropdown can open upward. */ - upward: boolean; + upward?: boolean; } interface DropdownComponent extends React.ComponentClass { diff --git a/src/modules/Dropdown/Dropdown.js b/src/modules/Dropdown/Dropdown.js index f709137f00..3e487aebd7 100644 --- a/src/modules/Dropdown/Dropdown.js +++ b/src/modules/Dropdown/Dropdown.js @@ -312,9 +312,6 @@ export default class Dropdown extends Component { PropTypes.node, ]), - /** A dropdown can open upward. */ - upward: PropTypes.bool, - /** Current value or value array if multiple. Creates a controlled component. */ value: PropTypes.oneOfType([ PropTypes.string, @@ -324,6 +321,9 @@ export default class Dropdown extends Component { PropTypes.number, ])), ]), + + /** A dropdown can open upward. */ + upward: PropTypes.bool, } static defaultProps = { diff --git a/src/modules/Modal/Modal.d.ts b/src/modules/Modal/Modal.d.ts index 83cdb92adc..831882bc3e 100644 --- a/src/modules/Modal/Modal.d.ts +++ b/src/modules/Modal/Modal.d.ts @@ -34,7 +34,7 @@ export interface ModalProps extends PortalProps { closeOnDocumentClick?: boolean; /** A Modal can be passed content via shorthand. */ - content: any; + content?: any; /** Initial value of open. */ defaultOpen?: boolean; @@ -43,7 +43,7 @@ export interface ModalProps extends PortalProps { dimmer?: boolean | 'blurring' | 'inverted'; /** A Modal can be passed header via shorthand. */ - header: any; + header?: any; /** The node where the modal should mount. Defaults to document.body. */ mountNode?: any; diff --git a/src/modules/Modal/ModalActions.d.ts b/src/modules/Modal/ModalActions.d.ts index 47614184c9..1277f0c236 100644 --- a/src/modules/Modal/ModalActions.d.ts +++ b/src/modules/Modal/ModalActions.d.ts @@ -22,7 +22,7 @@ export interface ModalActionsProps { * @param {SyntheticEvent} event - React's original SyntheticEvent. * @param {object} data - All item props. */ - onItemClick?: (event: React.MouseEvent, data: ButtonProps) => void; + onActionClick?: (event: React.MouseEvent, data: ButtonProps) => void; } declare const ModalActions: React.ComponentClass; diff --git a/src/modules/Modal/ModalContent.d.ts b/src/modules/Modal/ModalContent.d.ts index b7c342d4c9..b6c0f6cd7d 100644 --- a/src/modules/Modal/ModalContent.d.ts +++ b/src/modules/Modal/ModalContent.d.ts @@ -12,6 +12,9 @@ export interface ModalContentProps { /** Additional classes. */ className?: string; + /** Shorthand for primary content. */ + content?: any; + /** A modal can contain image content. */ image?: boolean; } diff --git a/src/views/Advertisement/Advertisement.d.ts b/src/views/Advertisement/Advertisement.d.ts index abba468854..9d3e688796 100644 --- a/src/views/Advertisement/Advertisement.d.ts +++ b/src/views/Advertisement/Advertisement.d.ts @@ -9,6 +9,9 @@ export interface AdvertisementProps { /** Center the advertisement. */ centered?: boolean; + /** Primary content. */ + children?: React.ReactNode; + /** Additional classes. */ className?: string; @@ -16,7 +19,7 @@ export interface AdvertisementProps { test?: boolean | string | number; /** Varies the size of the advertisement. */ - unit?: 'medium rectangle' | 'large rectangle' | 'vertical rectangle' | 'small rectangle' | + unit: 'medium rectangle' | 'large rectangle' | 'vertical rectangle' | 'small rectangle' | 'mobile banner' | 'banner' | 'vertical banner' | 'top banner' | 'half banner'| 'button' | 'square button' | 'small button'| 'skyscraper' | 'wide skyscraper' | diff --git a/src/views/Item/Item.js b/src/views/Item/Item.js index f74f713eb5..3419443c16 100644 --- a/src/views/Item/Item.js +++ b/src/views/Item/Item.js @@ -87,12 +87,12 @@ Item.propTypes = { /** Shorthand for ItemExtra component. */ extra: customPropTypes.itemShorthand, - /** Shorthand for ItemImage component. */ - image: customPropTypes.itemShorthand, - /** Shorthand for ItemHeader component. */ header: customPropTypes.itemShorthand, + /** Shorthand for ItemImage component. */ + image: customPropTypes.itemShorthand, + /** Shorthand for ItemMeta component. */ meta: customPropTypes.itemShorthand, } diff --git a/src/views/Statistic/Statictic.d.ts b/src/views/Statistic/Statistic.d.ts similarity index 100% rename from src/views/Statistic/Statictic.d.ts rename to src/views/Statistic/Statistic.d.ts diff --git a/src/views/Statistic/index.d.ts b/src/views/Statistic/index.d.ts index bba21c6c97..fdb0cc818e 100644 --- a/src/views/Statistic/index.d.ts +++ b/src/views/Statistic/index.d.ts @@ -1 +1 @@ -export { default, StatisticProps } from './Statictic'; +export { default, StatisticProps } from './Statistic'; diff --git a/test/specs/commonTests/hasValidTypings.js b/test/specs/commonTests/hasValidTypings.js new file mode 100644 index 0000000000..7a64a07064 --- /dev/null +++ b/test/specs/commonTests/hasValidTypings.js @@ -0,0 +1,70 @@ +import _ from 'lodash' +import path from 'path' + +import componentInfo from './componentInfo' +import { + getNodes, + getInterfaces, + requireTs, +} from './tsHelpers' + +/** + * Assert Component has the valid typings. + * @param {React.Component|Function} Component A component that should conform. + * @param {Object} [extractedInfo={}] + * @param {Object} [extractedInfo._meta={}] The meta information about Component + * @param {Object} [options={}] + * @param {Object} [options.requiredProps={}] Props required to render Component without errors or warnings. + */ +export default (Component, extractedInfo, options = {}) => { + const { + _meta: { name: componentName }, + filenameWithoutExt, + filePath, + } = extractedInfo || _.find(componentInfo, i => i.constructorName === Component.prototype.constructor.name) + const { requiredProps } = options + + const tsFile = filenameWithoutExt + '.d.ts' + const tsContent = requireTs(path.join(path.dirname(filePath), tsFile)) + + describe('typings', () => { + describe('structure', () => { + it(`${tsFile} exists`, () => { + tsContent.should.to.not.equal(false) + }) + }) + + const tsNodes = getNodes(tsFile, tsContent) + const interfaceName = `${componentName}Props` + const interfaceObject = _.find(getInterfaces(tsNodes), { name: interfaceName }) || {} + + describe(`interface ${interfaceName}`, () => { + it('has interface', () => { + interfaceObject.should.to.be.an('object') + }) + + it('is exported', () => { + const { exported } = interfaceObject + exported.should.to.equal(true) + }) + }) + + describe('props', () => { + const { props: interfaceProps } = interfaceObject + + it('are correctly defined', () => { + const componentPropTypes = _.get(Component, 'propTypes') + const componentProps = _.keys(componentPropTypes) + + componentProps.should.to.deep.equal(_.map(interfaceProps, 'name')) + }) + + it('only necessary are required', () => { + const componentRequired = _.keys(requiredProps) + const interfaceRequired = _.filter(interfaceProps, ['required', true]) + + componentRequired.should.to.deep.equal(_.map(interfaceRequired, 'name')) + }) + }) + }) +} diff --git a/test/specs/commonTests/index.js b/test/specs/commonTests/index.js index 0327a628ac..8440cdb207 100644 --- a/test/specs/commonTests/index.js +++ b/test/specs/commonTests/index.js @@ -1,4 +1,5 @@ export hasSubComponents from './hasSubComponents' +export hasValidTypings from './hasValidTypings' export hasUIClassName from './hasUIClassName' export * from './implementsClassNameProps' diff --git a/test/specs/commonTests/isConformant.js b/test/specs/commonTests/isConformant.js index cc71c1ffa7..9c49b78f4f 100644 --- a/test/specs/commonTests/isConformant.js +++ b/test/specs/commonTests/isConformant.js @@ -7,6 +7,7 @@ import * as semanticUIReact from 'semantic-ui-react' import { META } from 'src/lib' import helpers from './commonHelpers' import componentInfo from './componentInfo' +import hasValidTypings from './hasValidTypings' import { consoleUtil, sandbox, syntheticEvent } from 'test/utils' /** @@ -30,12 +31,13 @@ export default (Component, options = {}) => { } // extract componentInfo for this component + const extractedInfo = _.find(componentInfo, i => i.constructorName === Component.prototype.constructor.name) const { _meta, constructorName, componentClassName, filenameWithoutExt, - } = _.find(componentInfo, i => i.constructorName === Component.prototype.constructor.name) + } = extractedInfo // ---------------------------------------- // Class and file name @@ -339,4 +341,9 @@ export default (Component, options = {}) => { }) }) }) + + // ---------------------------------------- + // Test typings + // ---------------------------------------- + hasValidTypings(Component, extractedInfo, options) } diff --git a/test/specs/commonTests/tsHelpers.js b/test/specs/commonTests/tsHelpers.js new file mode 100644 index 0000000000..d54f68e5ab --- /dev/null +++ b/test/specs/commonTests/tsHelpers.js @@ -0,0 +1,56 @@ +import _ from 'lodash' +import { + createSourceFile, + forEachChild, + ScriptTarget, + SyntaxKind, +} from 'typescript' + +const isInterface = ({ kind }) => kind === SyntaxKind.InterfaceDeclaration + +const isExportModifier = ({ kind }) => kind === SyntaxKind.ExportKeyword + +const isPropertySignature = ({ kind }) => kind === SyntaxKind.PropertySignature + +const getProps = members => { + const props = _.filter(members, isPropertySignature) + + return _.map(props, ({ name, questionToken }) => ({ + name: name.text, + required: !questionToken, + })) +} + +const walkNode = (node, nodes) => forEachChild(node, child => { + nodes.push(child) + walkNode(child, nodes) + + return false +}) + +export const getNodes = (tsFile, tsContent) => { + const nodes = [] + const tsSource = createSourceFile(tsFile, tsContent, ScriptTarget.Latest, true) + + walkNode(tsSource, nodes) + + return nodes +} + +export const getInterfaces = nodes => { + const interfaces = _.filter(nodes, isInterface) + + return _.map(interfaces, ({ members, modifiers, name }) => ({ + exported: _.some(modifiers, isExportModifier), + name: name.text, + props: getProps(members), + })) +} + +export const requireTs = tsPath => { + try { + return require(`!raw-loader!../../../src/${tsPath}`) + } catch (e) { + return false + } +} diff --git a/test/specs/modules/Modal/Modal-test.js b/test/specs/modules/Modal/Modal-test.js index 279638dab4..ce00671332 100644 --- a/test/specs/modules/Modal/Modal-test.js +++ b/test/specs/modules/Modal/Modal-test.js @@ -45,6 +45,8 @@ describe('Modal', () => { }) common.hasSubComponents(Modal, [ModalHeader, ModalContent, ModalActions, ModalDescription]) + common.hasValidTypings(Modal) + common.implementsShorthandProp(Modal, { propKey: 'header', ShorthandComponent: ModalHeader, diff --git a/webpack.config.js b/webpack.config.js index c7a434e388..d5577b896c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -152,6 +152,7 @@ webpackConfig.module.noParse = [...webpackConfig.module.noParse, /\.json$/, /anchor-js/, /babel-standalone/, + /typescript\/lib/, ] if (!__TEST__) {