diff --git a/jest/unit/components/__mocks__/api.ts b/jest/unit/components/__mocks__/api.ts index e4816c0..d1bcd61 100644 --- a/jest/unit/components/__mocks__/api.ts +++ b/jest/unit/components/__mocks__/api.ts @@ -39,8 +39,8 @@ const register = (url, method = 'get', options = {}) => { * Bind API methods */ class API { - request() { - return register.call(null, ...arguments); + public request(...rest) { + return register.call(null, ...rest); } } diff --git a/jest/unit/components/store/logo.ts b/jest/unit/components/store/logo.ts index ac64387..3a07b37 100644 --- a/jest/unit/components/store/logo.ts +++ b/jest/unit/components/store/logo.ts @@ -2,6 +2,6 @@ * Mock response for logo api * @returns {promise} */ -export default function() { +export default function(): Promise { return Promise.resolve('http://localhost/-/static/logo.png'); } diff --git a/src/App/App.test.tsx b/src/App/App.test.tsx index 91d302d..4f629fb 100644 --- a/src/App/App.test.tsx +++ b/src/App/App.test.tsx @@ -7,7 +7,7 @@ import { generateTokenWithTimeRange } from '../../jest/unit/components/__mocks__ jest.mock('../utils/storage', () => { class LocalStorageMock { - store: object; + private store: object; public constructor() { this.store = {}; } @@ -43,7 +43,7 @@ describe('App', () => { expect(wrapper.state().showLoginModal).toBeFalsy(); handleToggleLoginModal(); expect(wrapper.state('showLoginModal')).toBeTruthy(); - expect(wrapper.state('error')).toEqual({}); + expect(wrapper.state('error')).toEqual(undefined); }); test('isUserAlreadyLoggedIn: token already available in storage', async () => { diff --git a/src/App/App.tsx b/src/App/App.tsx index b75ddc4..aee581a 100644 --- a/src/App/App.tsx +++ b/src/App/App.tsx @@ -14,14 +14,26 @@ import '../styles/typeface-roboto.scss'; import '../styles/main.scss'; import 'normalize.css'; import Footer from '../components/Footer'; +import { FormError } from 'src/components/Login/Login'; -export const AppContext = React.createContext(null); +export const AppContext = React.createContext<{}>({}); export const AppContextProvider = AppContext.Provider; export const AppContextConsumer = AppContext.Consumer; -export default class App extends Component { - public state = { - error: {}, +export interface AppStateInterface { + error?: FormError; + logoUrl: string; + user: { + username?: string; + }; + scope: string; + showLoginModal: boolean; + isUserLoggedIn: boolean; + packages: []; + isLoading: boolean; +} +export default class App extends Component<{}, AppStateInterface> { + public state: AppStateInterface = { // @ts-ignore logoUrl: window.VERDACCIO_LOGO, user: {}, @@ -49,7 +61,7 @@ export default class App extends Component { public render(): React.ReactElement { const { isLoading, isUserLoggedIn, packages, logoUrl, user, scope } = this.state; - const context: any = { isUserLoggedIn, packages, logoUrl, user, scope }; + const context = { isUserLoggedIn, packages, logoUrl, user, scope }; return ( // @ts-ignore @@ -112,7 +124,6 @@ export default class App extends Component { this.setState(prevState => ({ // @ts-ignore showLoginModal: !prevState.showLoginModal, - error: {}, })); }; diff --git a/src/components/ActionBar/ActionBar.tsx b/src/components/ActionBar/ActionBar.tsx index 9c8aff3..b8a0fbf 100644 --- a/src/components/ActionBar/ActionBar.tsx +++ b/src/components/ActionBar/ActionBar.tsx @@ -25,7 +25,7 @@ const ACTIONS = { }, }; -class ActionBar extends Component { +class ActionBar extends Component { public render(): ReactElement { return ( @@ -36,7 +36,7 @@ class ActionBar extends Component { ); } - private renderIconsWithLink(link: string, component: any): ReactElement { + private renderIconsWithLink(link: string, component: JSX.Element): ReactElement { return ( {component} diff --git a/src/components/Author/Author.tsx b/src/components/Author/Author.tsx index 890fbdb..e39d739 100644 --- a/src/components/Author/Author.tsx +++ b/src/components/Author/Author.tsx @@ -1,4 +1,4 @@ -import React, { Component, ReactNode } from 'react'; +import React, { Component, ReactNode, ReactElement } from 'react'; import Avatar from '@material-ui/core/Avatar'; import List from '@material-ui/core/List'; @@ -8,18 +8,18 @@ import { DetailContextConsumer } from '../../pages/version/Version'; import { Heading, AuthorListItem } from './styles'; import { isEmail } from '../../utils/url'; -class Authors extends Component { - render() { +class Authors extends Component { + public render(): ReactElement { return ( - {(context: any) => { + {context => { return context && context.packageMeta && this.renderAuthor(context.packageMeta); }} ); } - renderLinkForMail(email: string, avatarComponent: ReactNode, packageName: string, version: string) { + public renderLinkForMail(email: string, avatarComponent: ReactNode, packageName: string, version: string): ReactElement | ReactNode { if (!email || isEmail(email) === false) { return avatarComponent; } @@ -31,7 +31,7 @@ class Authors extends Component { ); } - renderAuthor = packageMeta => { + public renderAuthor = packageMeta => { const { author, name: packageName, version } = packageMeta.latest; if (!author) { diff --git a/src/components/AutoComplete/AutoComplete.tsx b/src/components/AutoComplete/AutoComplete.tsx index 350c332..7fc2eb7 100644 --- a/src/components/AutoComplete/AutoComplete.tsx +++ b/src/components/AutoComplete/AutoComplete.tsx @@ -7,8 +7,8 @@ import MenuItem from '@material-ui/core/MenuItem'; import { fontWeight } from '../../utils/styles/sizes'; import { Wrapper, InputField, SuggestionContainer } from './styles'; -export interface Props { - suggestions: any[]; +interface Props { + suggestions: unknown[]; suggestionsLoading?: boolean; suggestionsLoaded?: boolean; suggestionsError?: boolean; @@ -16,17 +16,17 @@ export interface Props { color?: string; value?: string; placeholder?: string; - startAdornment?: any; + startAdornment?: JSX.Element; disableUnderline?: boolean; onChange?: (event: KeyboardEvent, { newValue, method }: { newValue: string; method: string }) => void; onSuggestionsFetch?: ({ value: string }) => Promise; onCleanSuggestions?: () => void; - onClick?: (event: KeyboardEvent, { suggestionValue, method }: { suggestionValue: any[]; method: string }) => void; + onClick?: (event: KeyboardEvent, { suggestionValue, method }: { suggestionValue: string[]; method: string }) => void; onKeyDown?: (event: KeyboardEvent) => void; onBlur?: (event: KeyboardEvent) => void; } -const renderInputComponent = inputProps => { +const renderInputComponent = (inputProps): JSX.Element => { const { ref, startAdornment, disableUnderline, onKeyDown, ...others } = inputProps; return ( { const getSuggestionValue = (suggestion): string => suggestion.name; -const renderSuggestion = (suggestion, { query, isHighlighted }) => { +const renderSuggestion = (suggestion, { query, isHighlighted }): JSX.Element => { const matches = match(suggestion.name, query); const parts = parse(suggestion.name, matches); return ( @@ -68,7 +68,7 @@ const renderSuggestion = (suggestion, { query, isHighlighted }) => { ); }; -const renderMessage = message => { +const renderMessage = (message): JSX.Element => { return (
{message}
@@ -98,7 +98,7 @@ const AutoComplete = ({ suggestionsLoading = false, suggestionsLoaded = false, suggestionsError = false, -}: Props) => { +}: Props): JSX.Element => { const autosuggestProps = { renderInputComponent, suggestions, @@ -119,7 +119,7 @@ const AutoComplete = ({ }; // this format avoid arrow function eslint rule - function renderSuggestionsContainer({ containerProps, children, query }) { + function renderSuggestionsContainer({ containerProps, children, query }): JSX.Element { return ( {suggestionsLoaded && children === null && query && renderMessage(SUGGESTIONS_RESPONSE.NO_RESULT)} diff --git a/src/components/CopyToClipBoard/CopyToClipBoard.tsx b/src/components/CopyToClipBoard/CopyToClipBoard.tsx index 24f648b..765e2b7 100644 --- a/src/components/CopyToClipBoard/CopyToClipBoard.tsx +++ b/src/components/CopyToClipBoard/CopyToClipBoard.tsx @@ -12,7 +12,7 @@ interface Props { children?: React.ReactNode; } -const renderText: React.FC = (text: string, children: React.ReactNode): React.ReactElement => { +const renderText = (text, children): JSX.Element => { if (children) { return {children}; } diff --git a/src/components/Dependencies/Dependencies.tsx b/src/components/Dependencies/Dependencies.tsx index 931a316..4033cf2 100644 --- a/src/components/Dependencies/Dependencies.tsx +++ b/src/components/Dependencies/Dependencies.tsx @@ -1,5 +1,5 @@ import React, { Component, Fragment, ReactElement } from 'react'; -import { withRouter } from 'react-router-dom'; +import { withRouter, RouteProps } from 'react-router-dom'; import CardContent from '@material-ui/core/CardContent'; import { DetailContextConsumer, VersionPageConsumerProps } from '../../pages/version/Version'; @@ -7,8 +7,19 @@ import { DetailContextConsumer, VersionPageConsumerProps } from '../../pages/ver import { CardWrap, Heading, Tags, Tag } from './styles'; import NoItems from '../NoItems'; -class DepDetail extends Component { - constructor(props: any) { +interface DepDetailProps { + name: string; + version: string; + onLoading: () => void; + history: string[]; +} +interface DepDetailState { + name: string; + version: string; +} + +class DepDetail extends Component { + constructor(props: DepDetailProps) { super(props); const { name, version } = this.props; @@ -33,16 +44,16 @@ class DepDetail extends Component { }; } -const WrapperDependencyDetail = withRouter(DepDetail); +const WrapperDependencyDetail = withRouter(DepDetail); -class DependencyBlock extends Component { +class DependencyBlock extends Component<{ title: string; dependencies: [] }> { public render(): ReactElement { const { dependencies, title } = this.props; - const deps = Object.entries(dependencies); + const deps = Object.entries(dependencies) as []; return ( - {({ enableLoading }: any) => { + {({ enableLoading }) => { return ( @@ -56,15 +67,15 @@ class DependencyBlock extends Component { ); } - private renderTags = (deps: any, enableLoading: any) => + private renderTags = (deps: [], enableLoading?: () => void) => deps.map(dep => { - const [name, version] = dep; + const [name, version] = dep as [string, string]; return ; }); } -class Dependencies extends Component { +class Dependencies extends Component { public state = { tabPosition: 0, }; @@ -79,7 +90,7 @@ class Dependencies extends Component { ); } - private checkDependencyLength(dependency: Record = {}): boolean { + private checkDependencyLength(dependency: Record = {}): boolean { return Object.keys(dependency).length > 0; } diff --git a/src/components/DetailContainer/DetailContainer.tsx b/src/components/DetailContainer/DetailContainer.tsx index b5945c1..e7e30fa 100644 --- a/src/components/DetailContainer/DetailContainer.tsx +++ b/src/components/DetailContainer/DetailContainer.tsx @@ -14,7 +14,7 @@ interface DetailContainerState { tabPosition: number; } -class DetailContainer extends Component { +class DetailContainer

extends Component { public state = { tabPosition: 0, }; @@ -29,7 +29,7 @@ class DetailContainer extends Component { ); } - private handleChange = (event: any, tabPosition: number) => { + private handleChange = (event: React.ChangeEvent<{}>, tabPosition: number) => { event.preventDefault(); this.setState({ tabPosition }); }; diff --git a/src/components/Developers/Developers.tsx b/src/components/Developers/Developers.tsx index 5881d77..68d87ca 100644 --- a/src/components/Developers/Developers.tsx +++ b/src/components/Developers/Developers.tsx @@ -11,18 +11,21 @@ import { isEmail } from '../../utils/url'; interface Props { type: 'contributors' | 'maintainers'; } +interface State { + visibleDevs: number; +} -class Developers extends Component { - state = { +class Developers extends Component { + public state = { visibleDevs: 6, }; - render() { + public render(): JSX.Element { return ( - {({ packageMeta }: any) => { + {({ packageMeta }) => { const { type } = this.props; - const developerType = packageMeta.latest[type]; + const developerType = packageMeta && packageMeta.latest[type]; if (!developerType || developerType.length === 0) return null; return this.renderDevelopers(developerType, packageMeta); }} @@ -30,11 +33,11 @@ class Developers extends Component { ); } - handleLoadMore = () => { + public handleLoadMore = () => { this.setState(prev => ({ visibleDevs: prev.visibleDevs + 6 })); }; - renderDevelopers = (developers, packageMeta) => { + private renderDevelopers = (developers, packageMeta) => { const { type } = this.props; const { visibleDevs } = this.state; return ( @@ -54,7 +57,7 @@ class Developers extends Component { ); }; - renderLinkForMail(email, avatarComponent, packageName, version) { + private renderLinkForMail(email, avatarComponent, packageName, version): JSX.Element { if (!email || isEmail(email) === false) { return avatarComponent; } @@ -65,7 +68,7 @@ class Developers extends Component { ); } - renderDeveloperDetails = ({ name, avatar, email }, packageMeta) => { + private renderDeveloperDetails = ({ name, avatar, email }, packageMeta) => { const { name: packageName, version } = packageMeta.latest; const avatarComponent = ; diff --git a/src/components/Dist/Dist.tsx b/src/components/Dist/Dist.tsx index 4921f2e..3b05cf4 100644 --- a/src/components/Dist/Dist.tsx +++ b/src/components/Dist/Dist.tsx @@ -2,22 +2,23 @@ import React, { Component } from 'react'; import List from '@material-ui/core/List'; -import { DetailContextConsumer } from '../../pages/version/Version'; +import { DetailContextConsumer, VersionPageConsumerProps } from '../../pages/version/Version'; import { Heading, DistListItem, DistChips } from './styles'; import fileSizeSI from '../../utils/file-size'; +import { PackageMetaInterface } from 'types/packageMeta'; -class Dist extends Component { - render() { +class Dist extends Component { + public render(): JSX.Element { return ( - {(context: any) => { - return this.renderDist(context); + {(context: Partial) => { + return context && context.packageMeta && this.renderDist(context.packageMeta); }} ); } - renderChips(dist: any, license: string) { + private renderChips(dist, license: string): JSX.Element | never[] { const distDict = { 'file-count': dist.fileCount, size: dist.unpackedSize && fileSizeSI(dist.unpackedSize), @@ -43,8 +44,8 @@ class Dist extends Component { return chipsList; } - renderDist = ({ packageMeta }: any) => { - const { dist = {}, license } = packageMeta.latest; + private renderDist = (packageMeta: PackageMetaInterface) => { + const { dist, license } = packageMeta && packageMeta.latest; return ( {'Latest Distribution'}}> diff --git a/src/components/Footer/Footer.tsx b/src/components/Footer/Footer.tsx index 275485f..fe1c4cf 100644 --- a/src/components/Footer/Footer.tsx +++ b/src/components/Footer/Footer.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { Wrapper, Left, Right, Earth, Flags, Love, Flag, Logo, Inner, ToolTip } from './styles'; import { goToVerdaccioWebsite } from '../../utils/windows'; -const renderTooltip = () => ( +const renderTooltip = (): JSX.Element => ( @@ -22,7 +22,7 @@ const ON_LABEL = 'on'; const HEARTH_EMOJI = '♥'; // @ts-ignore -const renderRight = (version = window.VERDACCIO_VERSION) => { +const renderRight = (version = window.VERDACCIO_VERSION): JSX.Element => { return ( {POWERED_LABEL} @@ -32,7 +32,7 @@ const renderRight = (version = window.VERDACCIO_VERSION) => { ); }; -const renderLeft = () => ( +const renderLeft = (): JSX.Element => ( {MADEWITH_LABEL} {HEARTH_EMOJI} diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index de9f94c..4a1b30a 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -22,7 +22,7 @@ import RegistryInfoContent from '../RegistryInfoContent/RegistryInfoContent'; import { Greetings, NavBar, InnerNavBar, MobileNavBar, InnerMobileNavBar, LeftSide, RightSide, IconSearchButton, SearchWrapper } from './styles'; interface Props { - logo: string; + logo?: string; username?: string; onLogout: () => void; onToggleLoginModal: () => void; @@ -31,7 +31,7 @@ interface Props { } interface State { - anchorEl?: any; + anchorEl?: null | HTMLElement | ((element: HTMLElement) => HTMLElement); openInfoDialog: boolean; registryUrl: string; showMobileNavBar: boolean; diff --git a/src/components/Icon/Icon.tsx b/src/components/Icon/Icon.tsx index 830bd13..4c603c9 100644 --- a/src/components/Icon/Icon.tsx +++ b/src/components/Icon/Icon.tsx @@ -1,5 +1,6 @@ import React, { MouseEvent } from 'react'; import capitalize from 'lodash/capitalize'; +import { Breakpoint } from '@material-ui/core/styles/createBreakpoints'; import { Svg, Img, ImgWrapper } from './styles'; @@ -57,10 +58,10 @@ export interface Props { name: keyof IconsMap; className?: string; onClick?: (event: MouseEvent) => void; - size?: 'sm' | 'md'; + size?: Breakpoint; pointer?: boolean; img?: boolean; - modifiers?: any; + modifiers?: null | undefined; } const Icon: React.FC = ({ className, name, size = 'sm', img = false, pointer = false, ...props }) => { diff --git a/src/components/Icon/styles.ts b/src/components/Icon/styles.ts index ebb44c9..366190e 100644 --- a/src/components/Icon/styles.ts +++ b/src/components/Icon/styles.ts @@ -1,6 +1,9 @@ import styled, { css } from 'react-emotion'; +import { Breakpoint } from '@material-ui/core/styles/createBreakpoints'; +import { StyledOtherComponent } from 'create-emotion-styled'; +import { DetailedHTMLProps, HTMLAttributes } from 'react'; -const getSize = (size?: 'md' | 'sm') => { +const getSize = (size: Breakpoint): string => { switch (size) { case 'md': return ` @@ -15,7 +18,7 @@ const getSize = (size?: 'md' | 'sm') => { } }; -const commonStyle = ({ size = 'sm', pointer, modifiers }: any) => css` +const commonStyle = ({ size = 'sm' as Breakpoint, pointer, modifiers = null }): string => css` && { display: inline-block; cursor: ${pointer ? 'pointer' : 'default'}; @@ -30,7 +33,16 @@ export const Svg = styled('svg')` } `; -export const ImgWrapper = styled('span')` +export const ImgWrapper: StyledOtherComponent< + { + size?: Breakpoint; + pointer: boolean; + modifiers?: null | undefined; + name?: string | unknown; + }, + DetailedHTMLProps, HTMLSpanElement>, + {} +> = styled('span')` && { ${commonStyle}; } diff --git a/src/components/Install/Install.tsx b/src/components/Install/Install.tsx index 3b72c67..ee8ed59 100644 --- a/src/components/Install/Install.tsx +++ b/src/components/Install/Install.tsx @@ -3,7 +3,7 @@ import ListItemText from '@material-ui/core/ListItemText'; import React, { Component } from 'react'; // @ts-ignore -import { DetailContextConsumer } from '../../pages/version/Version'; +import { DetailContextConsumer, VersionPageConsumerProps } from '../../pages/version/Version'; import CopyToClipBoard from '../CopyToClipBoard'; // logos of package managers @@ -14,17 +14,17 @@ import yarn from './img/yarn.svg'; import { Heading, InstallItem, PackageMangerAvatar } from './styles'; class Install extends Component { - public render() { + public render(): JSX.Element { return ( - {(context: any) => { + {(context: Partial) => { return context && context.packageName && this.renderCopyCLI(context); }} ); } - public renderCopyCLI = ({ packageName }: { packageName: string }) => { + public renderCopyCLI = ({ packageName = '' }: Partial) => { return ( <> {'Installation'}}>{this.renderListItems(packageName)} diff --git a/src/components/Label/Label.tsx b/src/components/Label/Label.tsx index c9aa93b..95fa878 100644 --- a/src/components/Label/Label.tsx +++ b/src/components/Label/Label.tsx @@ -6,7 +6,7 @@ interface Props { text: string; capitalize?: boolean; weight?: string; - modifiers?: any; + modifiers?: null | undefined; } const Wrapper = styled('div')` diff --git a/src/components/Login/Login.test.tsx b/src/components/Login/Login.test.tsx index 03a9fce..7f8289a 100644 --- a/src/components/Login/Login.test.tsx +++ b/src/components/Login/Login.test.tsx @@ -63,7 +63,6 @@ describe('', () => { test('setCredentials - should set username and password in state', () => { const props = { visibility: true, - error: {}, onCancel: () => {}, onSubmit: () => {}, }; @@ -80,7 +79,6 @@ describe('', () => { test('validateCredentials: should validate credentials', async () => { const props = { visibility: true, - error: {}, onCancel: () => {}, onSubmit: jest.fn(), }; @@ -89,7 +87,7 @@ describe('', () => { const instance = wrapper.instance(); instance.submitCredentials = jest.fn(); - const { validateCredentials, setCredentials, submitCredentials } = instance; + const { handleValidateCredentials, setCredentials, submitCredentials } = instance; expect(setCredentials('username', eventUsername)).toBeUndefined(); expect(wrapper.state('form').username.value).toEqual('xyz'); @@ -97,7 +95,7 @@ describe('', () => { expect(setCredentials('password', eventPassword)).toBeUndefined(); expect(wrapper.state('form').password.value).toEqual('1234'); - validateCredentials(event); + handleValidateCredentials(event); expect(event.preventDefault).toHaveBeenCalled(); expect(wrapper.state('form').username.pristine).toEqual(false); expect(wrapper.state('form').password.pristine).toEqual(false); diff --git a/src/components/Login/Login.tsx b/src/components/Login/Login.tsx index d2806bf..9f56969 100644 --- a/src/components/Login/Login.tsx +++ b/src/components/Login/Login.tsx @@ -1,5 +1,4 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; import Button from '@material-ui/core/Button'; import DialogTitle from '@material-ui/core/DialogTitle'; import Dialog from '@material-ui/core/Dialog'; @@ -15,22 +14,35 @@ import FormHelperText from '@material-ui/core/FormHelperText'; // @ts-ignore import classes from './login.scss'; -export default class LoginModal extends Component { - static propTypes = { - visibility: PropTypes.bool, - error: PropTypes.object, - onCancel: PropTypes.func, - onSubmit: PropTypes.func, - }; +interface FormFields { + required: boolean; + pristine: boolean; + helperText: string; + value: string; +} +export interface FormError { + type: string; + title: string; + description: string; +} - static defaultProps = { - error: {}, - onCancel: () => {}, - onSubmit: () => {}, - visibility: true, - }; +interface LoginModalProps { + visibility: boolean; + error?: FormError; + onCancel: () => void; + onSubmit: (username: string, password: string) => void; +} - constructor(props) { +interface LoginModalState { + form: { + username: Partial; + password: Partial; + }; + error?: FormError; +} + +export default class LoginModal extends Component, LoginModalState> { + constructor(props: LoginModalProps) { super(props); this.state = { form: { @@ -51,11 +63,28 @@ export default class LoginModal extends Component { }; } + public render(): JSX.Element { + const { visibility = true, onCancel = () => null, error } = this.props as LoginModalProps; + return ( +

+
+ {'Login'} + + {error && this.renderLoginError(error)} + {this.renderNameField()} + {this.renderPasswordField()} + + {this.renderActions()} +
+
+ ); + } + /** * set login modal's username and password to current state * Required to login */ - setCredentials = (name, e) => { + public setCredentials = (name, e) => { const { form } = this.state; this.setState({ form: { @@ -69,15 +98,15 @@ export default class LoginModal extends Component { }); }; - setUsername = event => { + public handleUsernameChange = event => { this.setCredentials('username', event); }; - setPassword = event => { + public handlePasswordChange = event => { this.setCredentials('password', event); }; - validateCredentials = event => { + public handleValidateCredentials = event => { const { form } = this.state; // prevents default submit behavior event.preventDefault(); @@ -89,7 +118,7 @@ export default class LoginModal extends Component { ...acc, ...{ [key]: { ...form[key], pristine: false } }, }), - {} + { username: {}, password: {} } ), }, () => { @@ -100,10 +129,14 @@ export default class LoginModal extends Component { ); }; - submitCredentials = async () => { + public submitCredentials = async () => { const { form } = this.state; + const username = (form.username && form.username.value) || ''; + const password = (form.password && form.password.value) || ''; const { onSubmit } = this.props; - await onSubmit(form.username.value, form.password.value); + if (onSubmit) { + await onSubmit(username, password); + } // let's wait for API response and then set // username and password filed to empty state this.setState({ @@ -112,12 +145,12 @@ export default class LoginModal extends Component { ...acc, ...{ [key]: { ...form[key], value: '', pristine: true } }, }), - {} + { username: {}, password: {} } ), }); }; - renderErrorMessage(title, description) { + public renderErrorMessage(title, description): JSX.Element { return (
@@ -128,7 +161,7 @@ export default class LoginModal extends Component { ); } - renderMessage(title, description) { + public renderMessage(title, description): JSX.Element { return (
@@ -137,37 +170,37 @@ export default class LoginModal extends Component { ); } - renderLoginError({ type, title, description }) { + public renderLoginError({ type, title, description }: FormError): JSX.Element | false { return type === 'error' && ; } - renderNameField = () => { + public renderNameField = () => { const { form: { username }, } = this.state; return ( {'Username'} - + {!username.value && !username.pristine && {username.helperText}} ); }; - renderPasswordField = () => { + public renderPasswordField = () => { const { form: { password }, } = this.state; return ( {'Password'} - + {!password.value && !password.pristine && {password.helperText}} ); }; - renderActions = () => { + public renderActions = () => { const { form: { username, password }, } = this.state; @@ -183,21 +216,4 @@ export default class LoginModal extends Component { ); }; - - render() { - const { visibility, onCancel, error } = this.props; - return ( - -
- {'Login'} - - {this.renderLoginError(error)} - {this.renderNameField()} - {this.renderPasswordField()} - - {this.renderActions()} -
-
- ); - } } diff --git a/src/components/NotFound/NotFound.tsx b/src/components/NotFound/NotFound.tsx index da91ff0..b5fdd07 100644 --- a/src/components/NotFound/NotFound.tsx +++ b/src/components/NotFound/NotFound.tsx @@ -6,21 +6,22 @@ import { RouteComponentProps, withRouter } from 'react-router-dom'; import PackageImg from './img/package.svg'; import { Card, EmptyPackage, Heading, Inner, List, Wrapper } from './styles'; +import { Breakpoint } from '@material-ui/core/styles/createBreakpoints'; export const NOT_FOUND_TEXT = "Sorry, we couldn't find it..."; -export type NotFoundProps = RouteComponentProps & { width: any; history: any }; +export type NotFoundProps = RouteComponentProps & { width: Breakpoint; history }; const NotFound: React.FC = ({ history, width }) => { - const handleGoTo = (to: string) => () => { + const handleGoTo = (to: string): (() => void | undefined) => () => { history.push(to); }; - const handleGoBack = () => () => { + const handleGoBack = (): ((e: React.MouseEvent) => void | undefined) => () => { history.goBack(); }; - const renderList = () => ( + const renderList = (): JSX.Element => ( {'Home'} @@ -31,7 +32,7 @@ const NotFound: React.FC = ({ history, width }) => { ); - const renderSubTitle = () => ( + const renderSubTitle = (): JSX.Element => (
{"The page you're looking for doesn't exist."}
{'Perhaps these links will help find what you are looking for:'}
diff --git a/src/components/Package/Package.test.tsx b/src/components/Package/Package.test.tsx index 99ee5fe..bc29297 100644 --- a/src/components/Package/Package.test.tsx +++ b/src/components/Package/Package.test.tsx @@ -8,7 +8,7 @@ import { WrapperLink, Description, OverviewItem } from './styles'; * Generates one month back date from current time * @return {object} date object */ -const dateOneMonthAgo = () => new Date(1544377770747); +const dateOneMonthAgo = (): Date => new Date(1544377770747); describe(' component', () => { test.skip('should load the component', () => { diff --git a/src/components/Package/Package.tsx b/src/components/Package/Package.tsx index c01b02c..006d55f 100644 --- a/src/components/Package/Package.tsx +++ b/src/components/Package/Package.tsx @@ -23,10 +23,10 @@ interface Dist { unpackedSize: number; } -interface Props { +export interface PackageInterface { name: string; version: string; - time: string; + time?: number | string; author: Author; description?: string; keywords?: string[]; @@ -35,6 +35,7 @@ interface Props { bugs?: Bugs; dist?: Dist; } +// interface Props {} & PackageInterface; import { Author, @@ -56,7 +57,7 @@ import { } from './styles'; import { isURL } from '../../utils/url'; -const Package: React.FC = ({ +const Package: React.FC = ({ author: { name: authorName, avatar: authorAvatar }, bugs, description, diff --git a/src/components/PackageList/PackageList.tsx b/src/components/PackageList/PackageList.tsx index 7c0e387..ef281a4 100644 --- a/src/components/PackageList/PackageList.tsx +++ b/src/components/PackageList/PackageList.tsx @@ -1,25 +1,21 @@ -import React, { Fragment } from 'react'; -import PropTypes from 'prop-types'; +import React, { Fragment, ReactElement } from 'react'; import Divider from '@material-ui/core/Divider'; import Package from '../Package'; import Help from '../Help'; import { formatLicense } from '../../utils/package'; +import { PackageInterface } from '../Package/Package'; // @ts-ignore import classes from './packageList.scss'; interface Props { - packages: any; + packages: PackageInterface[]; } export default class PackageList extends React.Component { - static propTypes = { - packages: PropTypes.array, - }; - - render() { + public render(): ReactElement { return (
{this.hasPackages() ? this.renderPackages() : }
@@ -27,20 +23,19 @@ export default class PackageList extends React.Component { ); } - hasPackages() { + private hasPackages(): boolean { const { packages } = this.props; return packages.length > 0; } - renderPackages = () => { + private renderPackages = () => { return <>{this.renderList()}; }; - renderList = () => { + private renderList = () => { const { packages } = this.props; return packages.map((pkg, i) => { - const { name, version, description, time, keywords, dist, homepage, bugs } = pkg; - const author = pkg.author; + const { name, version, description, time, keywords, dist, homepage, bugs, author } = pkg; // TODO: move format license to API side. const license = formatLicense(pkg.license); return ( diff --git a/src/components/RegistryInfoContent/RegistryInfoContent.tsx b/src/components/RegistryInfoContent/RegistryInfoContent.tsx index 9d64b76..2333fab 100644 --- a/src/components/RegistryInfoContent/RegistryInfoContent.tsx +++ b/src/components/RegistryInfoContent/RegistryInfoContent.tsx @@ -11,7 +11,7 @@ import { getCLISetRegistry, getCLIChangePassword, getCLISetConfigRegistry } from import { NODE_MANAGER } from '../../utils/constants'; /* eslint react/prop-types:0 */ -function TabContainer({ children }) { +function TabContainer({ children }): JSX.Element { return ( @@ -22,15 +22,20 @@ function TabContainer({ children }) { } class RegistryInfoContent extends Component { - state = { + public state = { tabPosition: 0, }; - render() { + public render(): JSX.Element { return
{this.renderTabs()}
; } - renderTabs() { + private handleChange = (event: React.ChangeEvent<{}>, tabPosition: number) => { + event.preventDefault(); + this.setState({ tabPosition }); + }; + + private renderTabs(): JSX.Element { const { scope, registryUrl } = this.props; const { tabPosition } = this.state; @@ -48,7 +53,7 @@ class RegistryInfoContent extends Component { ); } - renderNpmTab(scope: string, registryUrl: string) { + private renderNpmTab(scope: string, registryUrl: string): JSX.Element { return ( @@ -58,7 +63,7 @@ class RegistryInfoContent extends Component { ); } - renderPNpmTab(scope: string, registryUrl: string) { + private renderPNpmTab(scope: string, registryUrl: string): JSX.Element { return ( @@ -68,18 +73,13 @@ class RegistryInfoContent extends Component { ); } - renderYarnTab(scope: string, registryUrl: string) { + private renderYarnTab(scope: string, registryUrl: string): JSX.Element { return ( ); } - - handleChange = (event: any, tabPosition: number) => { - event.preventDefault(); - this.setState({ tabPosition }); - }; } export default RegistryInfoContent; diff --git a/src/components/RegistryInfoDialog/RegistryInfoDialog.tsx b/src/components/RegistryInfoDialog/RegistryInfoDialog.tsx index f2c7741..494fc7f 100644 --- a/src/components/RegistryInfoDialog/RegistryInfoDialog.tsx +++ b/src/components/RegistryInfoDialog/RegistryInfoDialog.tsx @@ -8,7 +8,7 @@ import { Props } from './types'; const LABEL = 'CLOSE'; -const RegistryInfoDialog: React.FC = ({ open = false, children, onClose }): any => ( +const RegistryInfoDialog: React.FC = ({ open = false, children, onClose }) => ( {'Register Info'} {children} diff --git a/src/components/Repository/Repository.tsx b/src/components/Repository/Repository.tsx index 444d46d..bac92fe 100644 --- a/src/components/Repository/Repository.tsx +++ b/src/components/Repository/Repository.tsx @@ -13,7 +13,7 @@ import { Heading, GithubLink, RepositoryListItem } from './styles'; import git from './img/git.png'; import { isURL } from '../../utils/url'; -class Repository extends Component { +class Repository extends Component { public render(): ReactElement { return ( @@ -33,12 +33,7 @@ class Repository extends Component { } private renderRepository = packageMeta => { - const { - repository: { - // @ts-ignore - url, - } = {}, - } = packageMeta.latest; + const { repository: { url = null } = {} } = packageMeta.latest; if (!url || isURL(url) === false) { return null; diff --git a/src/components/Search/Search.test.tsx b/src/components/Search/Search.test.tsx index 27eecdc..795d106 100644 --- a/src/components/Search/Search.test.tsx +++ b/src/components/Search/Search.test.tsx @@ -154,7 +154,7 @@ describe(' component test', () => { beforeEach(() => { jest.resetModules(); jest.doMock('lodash/debounce', () => { - return function debounceMock(fn, delay) { + return function debounceMock(fn) { return fn; }; }); diff --git a/src/components/Search/Search.tsx b/src/components/Search/Search.tsx index 5692cb7..ec11715 100644 --- a/src/components/Search/Search.tsx +++ b/src/components/Search/Search.tsx @@ -11,11 +11,15 @@ import colors from '../../utils/styles/colors'; export interface State { search: string; - suggestions: any[]; + suggestions: unknown[]; loading: boolean; loaded: boolean; error: boolean; } +interface AbortControllerInterface { + signal: () => void; + abort: () => void; +} export type cancelAllSearchRequests = () => void; export type handlePackagesClearRequested = () => void; @@ -31,8 +35,6 @@ const CONSTANTS = { }; export class Search extends Component, State> { - private requestList: any[]; - constructor(props: RouteComponentProps<{}>) { super(props); this.state = { @@ -96,7 +98,10 @@ export class Search extends Component, State> { /** * When an user select any package by clicking or pressing return key. */ - private handleClickSearch: handleClickSearch = (event, { suggestionValue, method }: any) => { + private handleClickSearch = ( + event: React.KeyboardEvent, + { suggestionValue, method }: { suggestionValue: string[]; method: string } + ): void | undefined => { const { history } = this.props; // stops event bubbling event.stopPropagation(); @@ -163,7 +168,9 @@ export class Search extends Component, State> { ); } - public getAdorment(): ReactElement { + private requestList: AbortControllerInterface[]; + + public getAdorment(): JSX.Element { return ( diff --git a/src/components/Spinner/styles.ts b/src/components/Spinner/styles.ts index 95585e1..b86364a 100644 --- a/src/components/Spinner/styles.ts +++ b/src/components/Spinner/styles.ts @@ -1,5 +1,5 @@ import CircularProgress from '@material-ui/core/CircularProgress'; -import styled, { css, Themed } from 'react-emotion'; +import styled, { css } from 'react-emotion'; import colors from '../../utils/styles/colors'; @@ -8,7 +8,7 @@ export const Wrapper = styled('div')` display: flex; align-items: center; justify-content: center; - ${(props): Themed => + ${props => // @ts-ignore props.centered && css` diff --git a/src/components/UpLinks/UpLinks.tsx b/src/components/UpLinks/UpLinks.tsx index d11e15d..c2b261b 100644 --- a/src/components/UpLinks/UpLinks.tsx +++ b/src/components/UpLinks/UpLinks.tsx @@ -8,7 +8,7 @@ import { formatDateDistance } from '../../utils/package'; import { Heading, Spacer, ListItemText } from './styles'; -class UpLinks extends React.PureComponent { +class UpLinks extends React.PureComponent<{}> { public render(): ReactElement { return ( diff --git a/src/components/Versions/Versions.tsx b/src/components/Versions/Versions.tsx index ac3f5ec..a9a21da 100644 --- a/src/components/Versions/Versions.tsx +++ b/src/components/Versions/Versions.tsx @@ -8,7 +8,7 @@ import { DIST_TAGS } from '../../../lib/constants'; const NOT_AVAILABLE = 'Not available'; -class Versions extends React.PureComponent { +class Versions extends React.PureComponent { public render(): ReactElement { return ( @@ -19,7 +19,7 @@ class Versions extends React.PureComponent { ); } - public renderPackageList = (packages: any, isVersion: boolean = false, timeMap: Record = {}): ReactElement => { + public renderPackageList = (packages: {}, isVersion: boolean = false, timeMap: Record = {}): ReactElement => { return ( {Object.keys(packages) diff --git a/src/index.tsx b/src/index.tsx index 610762a..7c1c83d 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -8,7 +8,7 @@ import App from './App'; const rootNode = document.getElementById('root'); -const renderApp = Component => { +const renderApp = (Component): void => { ReactDOM.render( diff --git a/src/pages/home/Home.tsx b/src/pages/home/Home.tsx index 3a696fb..cdc08e9 100644 --- a/src/pages/home/Home.tsx +++ b/src/pages/home/Home.tsx @@ -4,7 +4,7 @@ import PackageList from '../../components/PackageList'; interface Props { isUserLoggedIn: boolean; - packages: any[]; + packages: []; } const Home: React.FC = ({ packages }) => ( diff --git a/src/pages/version/Version.tsx b/src/pages/version/Version.tsx index 4ebea1f..56c7c2c 100644 --- a/src/pages/version/Version.tsx +++ b/src/pages/version/Version.tsx @@ -3,31 +3,44 @@ import Grid from '@material-ui/core/Grid'; import Loading from '../../components/Loading/Loading'; import DetailContainer from '../../components/DetailContainer/DetailContainer'; import DetailSidebar from '../../components/DetailSidebar/DetailSidebar'; -import { callDetailPage, DetailPage } from '../../utils/calls'; +import { callDetailPage } from '../../utils/calls'; import { getRouterPackageName } from '../../utils/package'; import NotFound from '../../components/NotFound'; +import { PackageMetaInterface } from '../../../types/packageMeta'; export interface DetailContextProps { - packageMeta: any; - readMe: any; + packageMeta: PackageMetaInterface; + readMe: string; packageName: string; enableLoading: () => void; } -export const DetailContext = React.createContext(null); +export const DetailContext = React.createContext>({}); export interface VersionPageConsumerProps { - packageMeta: any; - readMe: any; - packageName: any; - enableLoading: any; + packageMeta: PackageMetaInterface; + readMe: string; + packageName: string; + enableLoading: () => void; } -export const DetailContextProvider: Provider = DetailContext.Provider; -export const DetailContextConsumer: Consumer = DetailContext.Consumer; +export const DetailContextProvider: Provider> = DetailContext.Provider; +export const DetailContextConsumer: Consumer> = DetailContext.Consumer; -class VersionPage extends Component { - constructor(props: any) { +interface PropsInterface { + match: boolean; +} + +interface StateInterface { + readMe: string; + packageName: string; + packageMeta: PackageMetaInterface | null; + isLoading: boolean; + notFound: boolean; +} + +class VersionPage extends Component> { + constructor(props) { super(props); this.state = { @@ -39,7 +52,7 @@ class VersionPage extends Component { }; } - public static getDerivedStateFromProps(nextProps: any, prevState: any): any { + public static getDerivedStateFromProps(nextProps, prevState): { packageName?: string; isLoading: boolean; notFound?: boolean } | null { const { match } = nextProps; const packageName = getRouterPackageName(match); @@ -65,10 +78,10 @@ class VersionPage extends Component { } /* eslint no-unused-vars: 0 */ - public async componentDidUpdate(nextProps: any, prevState: any): Promise { + public async componentDidUpdate(nextProps, prevState: StateInterface): Promise { const { packageName } = this.state; if (packageName !== prevState.packageName) { - const { readMe, packageMeta } = await callDetailPage(packageName); + const { readMe, packageMeta } = (await callDetailPage(packageName)) as Partial; this.setState({ readMe, packageMeta, @@ -112,7 +125,7 @@ class VersionPage extends Component { }); try { - const { readMe, packageMeta } = await callDetailPage(packageName); + const { readMe, packageMeta } = (await callDetailPage(packageName)) as Partial; this.setState({ readMe, packageMeta, diff --git a/src/router.tsx b/src/router.tsx index 1a9618e..dcc0e2b 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -2,7 +2,7 @@ import React, { Component, ReactElement } from 'react'; import { Router, Route, Switch } from 'react-router-dom'; -import { AppContextConsumer } from './App/App'; +import { AppContextConsumer, AppStateInterface } from './App/App'; import { asyncComponent } from './utils/asyncComponent'; import history from './history'; @@ -12,7 +12,12 @@ const NotFound = asyncComponent(() => import('./components/NotFound')); const VersionPackage = asyncComponent(() => import('./pages/version/Version')); const HomePage = asyncComponent(() => import('./pages/home')); -class RouterApp extends Component { +interface RouterAppProps { + onLogout: () => void; + onToggleLoginModal: () => void; +} + +class RouterApp extends Component { public render(): ReactElement { return ( @@ -34,8 +39,8 @@ class RouterApp extends Component { return ( - {function renderConsumerVersionPage({ logoUrl, scope, user }: any) { - return
; + {function renderConsumerVersionPage({ logoUrl, scope = '', user }: Partial) { + return
; }} ); @@ -44,7 +49,7 @@ class RouterApp extends Component { public renderHomePage = (): ReactElement => { return ( - {function renderConsumerVersionPage({ isUserLoggedIn, packages }: any) { + {function renderConsumerVersionPage({ isUserLoggedIn, packages }: Partial) { // @ts-ignore return ; }} @@ -52,10 +57,10 @@ class RouterApp extends Component { ); }; - public renderVersionPage = (routerProps: any): ReactElement => { + public renderVersionPage = (routerProps): ReactElement => { return ( - {function renderConsumerVersionPage({ isUserLoggedIn }: any) { + {function renderConsumerVersionPage({ isUserLoggedIn }: Partial) { return ; }} diff --git a/src/utils/api.ts b/src/utils/api.ts index 0f9c16e..4713fc5 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -6,9 +6,9 @@ import '../../types'; * @param {object} response * @returns {promise} */ -function handleResponseType(response): Promise { +function handleResponseType(response: Response): Promise<[boolean, Blob | string]> | Promise { if (response.headers) { - const contentType = response.headers.get('Content-Type'); + const contentType = response.headers.get('Content-Type') as string; if (contentType.includes('application/pdf')) { return Promise.all([response.ok, response.blob()]); } @@ -25,16 +25,16 @@ function handleResponseType(response): Promise { } class API { - public request(url: string, method = 'GET', options: any = {}): Promise { + public request(url: string, method = 'GET', options?: RequestInit): Promise { if (!window.VERDACCIO_API_URL) { throw new Error('VERDACCIO_API_URL is not defined!'); } const token = storage.getItem('token'); - if (token) { - if (!options.headers) options.headers = {}; - - options.headers.authorization = `Bearer ${token}`; + const headers = new Headers(options && options.headers); + if (token && options && options.headers) { + headers.set('Authorization', `Bearer ${token}`); + options.headers = Object.assign(options.headers, headers); } if (!['http://', 'https://', '//'].some(prefix => url.startsWith(prefix))) { @@ -42,7 +42,7 @@ class API { url = window.VERDACCIO_API_URL + url; } - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { fetch(url, { method, credentials: 'same-origin', diff --git a/src/utils/asyncComponent.tsx b/src/utils/asyncComponent.tsx index af57a35..9789aa0 100644 --- a/src/utils/asyncComponent.tsx +++ b/src/utils/asyncComponent.tsx @@ -1,11 +1,11 @@ -import React from 'react'; +import React, { ComponentClass } from 'react'; -export function asyncComponent(getComponent) { +export function asyncComponent(getComponent): ComponentClass { return class AsyncComponent extends React.Component { - static Component = null; - state = { Component: AsyncComponent.Component }; + public static Component = null; + public state = { Component: AsyncComponent.Component }; - componentDidMount() { + public componentDidMount(): void { const { Component } = this.state; if (!Component) { getComponent() @@ -19,7 +19,8 @@ export function asyncComponent(getComponent) { }); } } - render() { + + public render(): JSX.Element | null { const { Component } = this.state; if (Component) { // eslint-disable-next-line verdaccio/jsx-spread diff --git a/src/utils/calls.ts b/src/utils/calls.ts index f081bd2..168fdde 100644 --- a/src/utils/calls.ts +++ b/src/utils/calls.ts @@ -1,8 +1,9 @@ import API from './api'; +import { PackageMetaInterface } from 'types/packageMeta'; export interface DetailPage { - readMe: any; - packageMeta: any; + readMe: string | {}; + packageMeta: PackageMetaInterface | {}; } export async function callDetailPage(packageName): Promise { diff --git a/src/utils/cli-utils.ts b/src/utils/cli-utils.ts index 1a313f6..de9471c 100644 --- a/src/utils/cli-utils.ts +++ b/src/utils/cli-utils.ts @@ -1,6 +1,6 @@ import { SyntheticEvent } from 'react'; -export const copyToClipBoardUtility = (str: string): any => (event: SyntheticEvent): void => { +export const copyToClipBoardUtility = (str: string): ((e: SyntheticEvent) => void) => (event: SyntheticEvent): void => { event.preventDefault(); const node = document.createElement('div'); diff --git a/src/utils/file-size.ts b/src/utils/file-size.ts index cf8ca22..ab84828 100644 --- a/src/utils/file-size.ts +++ b/src/utils/file-size.ts @@ -1,3 +1,3 @@ -export default function fileSizeSI(a?: any, b?: any, c?: any, d?: any, e?: any) { +export default function fileSizeSI(a: number, b?: typeof Math, c?: (p: number) => number, d?: number, e?: number): string { return ((b = Math), (c = b.log), (d = 1e3), (e = (c(a) / c(d)) | 0), a / b.pow(d, e)).toFixed(2) + ' ' + (e ? 'kMGTPEZY'[--e] + 'B' : 'Bytes'); } diff --git a/src/utils/login.ts b/src/utils/login.ts index ac24733..df4c0e7 100644 --- a/src/utils/login.ts +++ b/src/utils/login.ts @@ -5,30 +5,34 @@ import { Base64 } from 'js-base64'; import API from './api'; import { HEADERS } from '../../lib/constants'; -export function isTokenExpire(token?: any) { +interface PayloadInterface { + exp: number; +} + +export function isTokenExpire(token?: string): boolean { if (!isString(token)) { return true; } - let [, payload]: any = token.split('.'); + const [, payload] = token.split('.'); if (!payload) { return true; } + let exp: number; try { - payload = JSON.parse(Base64.decode(payload)); + exp = JSON.parse(Base64.decode(payload)).exp; } catch (error) { - // eslint-disable-next-line - console.error('Invalid token:', error, token); + console.error('Invalid token:', error, token); return true; } - if (!payload.exp || !isNumber(payload.exp)) { + if (!exp || !isNumber(exp)) { return true; } // Report as expire before (real expire time - 30s) - const jsTimestamp = payload.exp * 1000 - 30000; + const jsTimestamp = exp * 1000 - 30000; const expired = Date.now() >= jsTimestamp; return expired; diff --git a/src/utils/sec-utils.ts b/src/utils/sec-utils.ts index c2617ee..cae1067 100644 --- a/src/utils/sec-utils.ts +++ b/src/utils/sec-utils.ts @@ -1,6 +1,6 @@ import parseXSS from 'xss'; -export function preventXSS(text: string) { +export function preventXSS(text: string): string { const encodedText = parseXSS.filterXSS(text); return encodedText; diff --git a/src/utils/styles/mixings.ts b/src/utils/styles/mixings.ts index 44ec992..a273df1 100644 --- a/src/utils/styles/mixings.ts +++ b/src/utils/styles/mixings.ts @@ -1,7 +1,7 @@ /** * CSS to represent truncated text with an ellipsis. */ -export function ellipsis(width: string | number) { +export function ellipsis(width: string | number): {} { return { display: 'inline-block', maxWidth: width, @@ -24,7 +24,7 @@ interface SpacingShortHand { const positionMap = ['Top', 'Right', 'Bottom', 'Left']; -export function spacing(property: 'padding' | 'margin', ...values: SpacingShortHand[]) { +export function spacing(property: 'padding' | 'margin', ...values: SpacingShortHand[]): {} { const [firstValue = 0, secondValue = 0, thirdValue = 0, fourthValue = 0] = values; const valuesWithDefaults = [firstValue, secondValue, thirdValue, fourthValue]; let styles = {}; diff --git a/types/custom.d.ts b/types/custom.d.ts index a7c309f..bf77f9b 100644 --- a/types/custom.d.ts +++ b/types/custom.d.ts @@ -1,10 +1,7 @@ // https://stackoverflow.com/questions/44717164/unable-to-import-svg-files-in-typescript declare module '*.svg' { - const content: any; + const content: string; export default content; } -declare module '*.png' { - const content: any; - export default content; -} +declare module '*.png'; diff --git a/types/packageMeta.ts b/types/packageMeta.ts new file mode 100644 index 0000000..473c331 --- /dev/null +++ b/types/packageMeta.ts @@ -0,0 +1,11 @@ +export interface PackageMetaInterface { + latest: { + name: string; + dist: { + fileCount: number; + unpackedSize: number; + }; + license: string; + }; + _uplinks: {}; +}