Skip to content

Commit

Permalink
Initial adoption of TypeScript in the frontend (badges#3722)
Browse files Browse the repository at this point in the history
  • Loading branch information
paulmelnikow authored Jul 18, 2019
1 parent d4e17d4 commit 88fc4a7
Show file tree
Hide file tree
Showing 21 changed files with 469 additions and 74 deletions.
5 changes: 5 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,16 @@ jobs:
name: Prepare frontend tests
command: npm run defs && npm run features

- run:
name: Check types
command: npm run check-types:frontend

- run:
name: Frontend unit tests
environment:
mocha_reporter: mocha-junit-reporter
MOCHA_FILE: junit/frontend/results.xml
when: always
command: npm run test:frontend

- store_test_results:
Expand Down
12 changes: 10 additions & 2 deletions .eslintrc-frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins:
- import
- react-hooks

parser: 'babel-eslint'
parser: '@typescript-eslint/parser'

parserOptions:
sourceType: 'module'
Expand All @@ -14,10 +14,12 @@ extends:
- 'standard-jsx'
- 'standard-react'
- './.eslintrc.yml'
- 'plugin:@typescript-eslint/recommended'
- 'prettier/@typescript-eslint'

settings:
react:
version: '16.4'
version: '16.8'

rules:
no-console: 'error'
Expand All @@ -26,3 +28,9 @@ rules:
react/jsx-sort-props: 'error'
react-hooks/rules-of-hooks: 'error'
react-hooks/exhaustive-deps: 'error'

'@typescript-eslint/no-unused-vars': ['error', { 'args': 'none' }]

# Argh.
'@typescript-eslint/explicit-function-return-type': 'off'
'@typescript-eslint/no-object-literal-type-assertion': 'off'
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { shallow, render } from 'enzyme'
import { expect } from 'chai'
import * as common from './common'

// @ts-ignore
import '../enzyme-conf.spec'

describe('Common modules', function() {
Expand Down
22 changes: 13 additions & 9 deletions frontend/components/common.js → frontend/components/common.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react'
import PropTypes from 'prop-types'
import styled, { css, createGlobalStyle } from 'styled-components'

export const noAutocorrect = Object.freeze({
Expand Down Expand Up @@ -41,7 +40,13 @@ export const H3 = styled.h3`
font-style: italic;
`

const BadgeWrapper = styled.span`
interface BadgeWrapperProps {
height: string
display: string
clickable: boolean
}

const BadgeWrapper = styled.span<BadgeWrapperProps>`
padding: 2px;
height: ${({ height }) => height};
vertical-align: middle;
Expand All @@ -61,20 +66,19 @@ export function Badge({
height = '20px',
clickable = false,
...rest
}: {
src: string
alt?: string
display?: 'inline' | 'block' | 'inline-block'
height?: string
clickable?: boolean
}) {
return (
<BadgeWrapper clickable={clickable} display={display} height={height}>
{src ? <img alt={alt} src={src} {...rest} /> : nonBreakingSpace}
</BadgeWrapper>
)
}
Badge.propTypes = {
src: PropTypes.string.isRequired,
alt: PropTypes.string,
display: PropTypes.oneOf(['inline', 'block', 'inline-block']),
height: PropTypes.string,
clickable: PropTypes.bool,
}

export const StyledInput = styled.input`
height: 15px;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'

const BuilderOuterContainer = styled.div`
Expand All @@ -17,33 +16,31 @@ const BuilderInnerContainer = styled.div`
background: #eef;
`

const BuilderContainer = ({ children }) => (
<BuilderOuterContainer>
<BuilderInnerContainer>{children}</BuilderInnerContainer>
</BuilderOuterContainer>
)
BuilderContainer.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]),
export function BuilderContainer({
children,
}: {
children: JSX.Element[] | JSX.Element
}) {
return (
<BuilderOuterContainer>
<BuilderInnerContainer>{children}</BuilderInnerContainer>
</BuilderOuterContainer>
)
}

const labelFont = `
font-family: system-ui;
font-size: 11px;
`

const BuilderLabel = styled.label`
export const BuilderLabel = styled.label`
${labelFont}
text-transform: lowercase;
`

const BuilderCaption = styled.span`
export const BuilderCaption = styled.span`
${labelFont}
color: #999;
`

export { BuilderContainer, BuilderLabel, BuilderCaption }
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { shallow, render } from 'enzyme'
import { expect } from 'chai'
import Donate from './donate'

// @ts-ignore
import '../enzyme-conf.spec'

describe('<Donate />', function() {
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react'
import { Helmet } from 'react-helmet'
// @ts-ignore
import favicon from '../images/favicon.png'

const description = `We serve fast and scalable informational images as badges
Expand Down
3 changes: 0 additions & 3 deletions frontend/constants.js

This file was deleted.

1 change: 1 addition & 0 deletions frontend/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const baseUrl = process.env.GATSBY_BASE_URL || ''
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export function bareLink(badgeUrl, link, title = '') {
export function bareLink(badgeUrl: string, link?: string, title = '') {
return badgeUrl
}

export function html(badgeUrl, link, title) {
export function html(badgeUrl: string, link?: string, title?: string) {
// To be more robust, this should escape the title.
const alt = title ? ` alt="${title}"` : ''
const img = `<img${alt} src="${badgeUrl}">`
Expand All @@ -13,7 +13,7 @@ export function html(badgeUrl, link, title) {
}
}

export function markdown(badgeUrl, link, title) {
export function markdown(badgeUrl: string, link?: string, title?: string) {
const withoutLink = `![${title || ''}](${badgeUrl})`
if (link) {
return `[${withoutLink}](${link})`
Expand All @@ -22,7 +22,11 @@ export function markdown(badgeUrl, link, title) {
}
}

export function reStructuredText(badgeUrl, link, title) {
export function reStructuredText(
badgeUrl: string,
link?: string,
title?: string
) {
let result = `.. image:: ${badgeUrl}`
if (title) {
result += ` :alt: ${title}`
Expand All @@ -33,7 +37,7 @@ export function reStructuredText(badgeUrl, link, title) {
return result
}

function quoteAsciiDocAttribute(attr) {
function quoteAsciiDocAttribute(attr: string | null) {
if (attr == null) {
return 'None'
} else {
Expand All @@ -43,15 +47,21 @@ function quoteAsciiDocAttribute(attr) {
}

// lodash.mapvalues is huge!
function mapValues(obj, iteratee) {
const result = {}
function mapValues(
obj: { [k: string]: string | null },
iteratee: (value: string | null) => string
): { [k: string]: string } {
const result = {} as { [k: string]: string }
for (const k in obj) {
result[k] = iteratee(obj[k])
}
return result
}

export function renderAsciiDocAttributes(positional, named) {
export function renderAsciiDocAttributes(
positional: string[],
named: { [k: string]: string | null }
) {
// http://asciidoc.org/userguide.html#X21
const needsQuoting =
positional.some(attr => attr && attr.includes(',')) ||
Expand All @@ -73,14 +83,26 @@ export function renderAsciiDocAttributes(positional, named) {
}
}

export function asciiDoc(badgeUrl, link, title) {
export function asciiDoc(badgeUrl: string, link?: string, title?: string) {
const positional = title ? [title] : []
const named = link ? { link } : {}
const named = link ? { link } : ({} as { [k: string]: string })
const attrs = renderAsciiDocAttributes(positional, named)
return `image:${badgeUrl}${attrs}`
}

export function generateMarkup({ badgeUrl, link, title, markupFormat }) {
export type MarkupFormat = 'markdown' | 'rst' | 'asciidoc' | 'link' | 'html'

export function generateMarkup({
badgeUrl,
link,
title,
markupFormat,
}: {
badgeUrl: string
link?: string
title?: string
markupFormat: MarkupFormat
}) {
const generatorFn = {
markdown,
rst: reStructuredText,
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import pathToRegexp from 'path-to-regexp'
// `foo|bar|baz`, return an array with the options. If it can't be described
// as multiple-choice options, return `undefined`.
const basicChars = /^[A-za-z0-9-]+$/
export function patternToOptions(pattern) {
export function patternToOptions(pattern: string): string[] | undefined {
const split = pattern.split('|')
if (split.some(part => !part.match(basicChars))) {
return undefined
Expand All @@ -14,7 +14,7 @@ export function patternToOptions(pattern) {
}

// Removes regexp for named parameters.
export function removeRegexpFromPattern(pattern) {
export function removeRegexpFromPattern(pattern: string): string {
const tokens = pathToRegexp.parse(pattern)
const simplePattern = tokens
.map(token => {
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion frontend/require-all.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const walk = require('walkdir')
import walk from 'walkdir'

// Ensure all the frontend files get instrumented. Because `all: true` does
// not work correctly unless `nyc` does the instrumentation.
Expand Down
1 change: 1 addition & 0 deletions gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module.exports = {
'gatsby-plugin-catch-links',
'gatsby-plugin-styled-components',
'gatsby-plugin-remove-trailing-slashes',
'gatsby-plugin-typescript',
// This currently is not being used.
// {
// resolve: 'gatsby-source-filesystem',
Expand Down
Loading

0 comments on commit 88fc4a7

Please sign in to comment.