Stricten TS rules; format registerServiceWorker.js

This commit is contained in:
Mitchell Simon 2019-09-03 02:07:13 -04:00
parent a28a8916d9
commit 0e6f33b5a8
16 changed files with 108 additions and 84 deletions

View File

@ -1,4 +1,4 @@
import React from "react" import React, { Component, ReactNode } from "react"
import Header from "./components/Header" import Header from "./components/Header"
import Navbar from "./components/Navbar" import Navbar from "./components/Navbar"
@ -6,8 +6,8 @@ import Routes from "./routes"
import "./Website.css" import "./Website.css"
export default class Website extends React.Component { export default class Website extends Component {
public render() { public render(): ReactNode {
return ( return (
<div className="website"> <div className="website">
<div className="main-container"> <div className="main-container">

View File

@ -1,4 +1,4 @@
import React from "react" import React, { PureComponent, ReactNode } from "react"
import "./index.css" import "./index.css"
@ -7,8 +7,8 @@ type Props = {
children: string children: string
} }
export default class ClearButton extends React.PureComponent<Props> { export default class ClearButton extends PureComponent<Props> {
public render() { public render(): ReactNode {
return ( return (
<a className="clear-button" href={this.props.href}> <a className="clear-button" href={this.props.href}>
{this.props.children} {this.props.children}

View File

@ -1,11 +1,11 @@
import React from "react" import React, { PureComponent, ReactNode } from "react"
import SmallText from "../SmallText" import SmallText from "../SmallText"
import "./index.css" import "./index.css"
export default class Header extends React.PureComponent { export default class Header extends PureComponent {
public render() { public render(): ReactNode {
return ( return (
<div className="header-container"> <div className="header-container">
<h2>Mitchell J. F. Simon</h2> <h2>Mitchell J. F. Simon</h2>

View File

@ -1,4 +1,4 @@
import * as React from "react" import React, { PureComponent, ReactNode } from "react"
import SmallText from "../../components/SmallText" import SmallText from "../../components/SmallText"
import "./index.css" import "./index.css"
@ -10,8 +10,8 @@ type Props = {
bullets: string[] bullets: string[]
} }
export default class Experience extends React.PureComponent<Props> { export default class Experience extends PureComponent<Props> {
public render() { public render(): ReactNode {
return ( return (
<div className="job-container"> <div className="job-container">
<div className="job-title">{this.props.title}</div> <div className="job-title">{this.props.title}</div>
@ -22,8 +22,8 @@ export default class Experience extends React.PureComponent<Props> {
) )
} }
private renderBullets() { private renderBullets(): ReactNode[] {
return this.props.bullets.map((bullet, index) => ( return this.props.bullets.map((bullet: string, index: number) => (
<li key={index}>{bullet}</li> <li key={index}>{bullet}</li>
)) ))
} }

View File

@ -1,16 +1,16 @@
import { faBars } from "@fortawesome/free-solid-svg-icons" import { faBars } from "@fortawesome/free-solid-svg-icons"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import * as React from "react" import React, { Component, ReactNode } from "react"
import { NavLink } from "react-router-dom" import { NavLink } from "react-router-dom"
import { routes } from "../../routes/routes" import { Route, routes } from "../../routes/routes"
import "./index.css" import "./index.css"
type State = { type State = {
showMenu: boolean showMenu: boolean
} }
class Navbar extends React.Component<{}, State> { export default class Navbar extends Component<{}, State> {
constructor(props: {}) { constructor(props: {}) {
super(props) super(props)
this.state = { showMenu: !this.isMobile() } this.state = { showMenu: !this.isMobile() }
@ -21,7 +21,7 @@ class Navbar extends React.Component<{}, State> {
this.menuButton = this.menuButton.bind(this) this.menuButton = this.menuButton.bind(this)
} }
public render() { public render(): ReactNode {
return ( return (
<div className="navbar"> <div className="navbar">
{this.menuButton()} {this.menuButton()}
@ -32,7 +32,7 @@ class Navbar extends React.Component<{}, State> {
) )
} }
private menuButton() { private menuButton(): ReactNode {
if (this.isMobile()) { if (this.isMobile()) {
return ( return (
<div <div
@ -51,19 +51,19 @@ class Navbar extends React.Component<{}, State> {
return null return null
} }
private isMobile() { private isMobile(): boolean {
const mobileMenuMaximum = 800 const mobileMenuMaximum = 800
return window.innerWidth <= mobileMenuMaximum return window.innerWidth <= mobileMenuMaximum
} }
private toggleMenu() { private toggleMenu(): void {
if (this.isMobile() || !this.state.showMenu) { if (this.isMobile() || !this.state.showMenu) {
this.setState(prev => ({ showMenu: !prev.showMenu })) this.setState((prev: State) => ({ showMenu: !prev.showMenu }))
} }
} }
private renderButtons() { private renderButtons(): ReactNode {
return routes.map(route => ( return routes.map((route: Route) => (
<NavLink <NavLink
key={route.name} key={route.name}
className="navbar-menu-button" className="navbar-menu-button"
@ -77,12 +77,10 @@ class Navbar extends React.Component<{}, State> {
)) ))
} }
private closeMenu() { private closeMenu(): void {
window.scrollTo(0, 0) window.scrollTo(0, 0)
if (this.isMobile()) { if (this.isMobile()) {
this.setState({ showMenu: false }) this.setState({ showMenu: false })
} }
} }
} }
export default Navbar

View File

@ -1,4 +1,4 @@
import * as React from "react" import React, { PureComponent, ReactNode } from "react"
import ClearButton from "../../components/ClearButton" import ClearButton from "../../components/ClearButton"
@ -17,8 +17,8 @@ type Props = {
badges: Badge[] badges: Badge[]
} }
export default class Project extends React.PureComponent<Props> { export default class Project extends PureComponent<Props> {
public render() { public render(): ReactNode {
return ( return (
<div className="project-container"> <div className="project-container">
<h4>{this.props.title}</h4> <h4>{this.props.title}</h4>
@ -29,8 +29,8 @@ export default class Project extends React.PureComponent<Props> {
) )
} }
private renderBadges(badges: Badge[]) { private renderBadges(badges: Badge[]): ReactNode[] {
return this.props.badges.map((badge, index) => ( return badges.map((badge: Badge, index: number) => (
<a className="project-badge" href={badge.linkUrl} key={index}> <a className="project-badge" href={badge.linkUrl} key={index}>
<img src={badge.imgUrl} alt={badge.alt} /> <img src={badge.imgUrl} alt={badge.alt} />
</a> </a>

View File

@ -1,10 +1,9 @@
// @flow import React, { PureComponent, ReactNode } from "react"
import React from "react"
import "./index.css" import "./index.css"
export default class SmallText extends React.PureComponent { export default class SmallText extends PureComponent {
public render() { public render(): ReactNode {
return <div className="small-text">{this.props.children}</div> return <div className="small-text">{this.props.children}</div>
} }
} }

View File

@ -9,9 +9,9 @@
// This link also includes instructions on opting out of this behavior. // This link also includes instructions on opting out of this behavior.
const isLocalhost = Boolean( const isLocalhost = Boolean(
window.location.hostname === 'localhost' || window.location.hostname === "localhost" ||
// [::1] is the IPv6 localhost address. // [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' || window.location.hostname === "[::1]" ||
// 127.0.0.1/8 is considered localhost for IPv4. // 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match( window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
@ -19,7 +19,7 @@ const isLocalhost = Boolean(
) )
export default function register() { export default function register() {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
// The URL constructor is available in all browsers that support SW. // The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location) // eslint-disable-line no-undef const publicUrl = new URL(process.env.PUBLIC_URL, window.location) // eslint-disable-line no-undef
if (publicUrl.origin !== window.location.origin) { if (publicUrl.origin !== window.location.origin) {
@ -29,7 +29,7 @@ export default function register () {
return return
} }
window.addEventListener('load', () => { window.addEventListener("load", () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js` const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`
if (isLocalhost) { if (isLocalhost) {
@ -40,8 +40,8 @@ export default function register () {
// service worker/PWA documentation. // service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => { navigator.serviceWorker.ready.then(() => {
console.log( console.log(
'This web app is being served cache-first by a service ' + "This web app is being served cache-first by a service " +
'worker. To learn more, visit https://goo.gl/SC7cgQ' "worker. To learn more, visit https://goo.gl/SC7cgQ"
) )
}) })
} else { } else {
@ -59,25 +59,25 @@ function registerValidSW (swUrl) {
registration.onupdatefound = () => { registration.onupdatefound = () => {
const installingWorker = registration.installing const installingWorker = registration.installing
installingWorker.onstatechange = () => { installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') { if (installingWorker.state === "installed") {
if (navigator.serviceWorker.controller) { if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and // At this point, the old content will have been purged and
// the fresh content will have been added to the cache. // the fresh content will have been added to the cache.
// It's the perfect time to display a "New content is // It's the perfect time to display a "New content is
// available; please refresh." message in your web app. // available; please refresh." message in your web app.
console.log('New content is available; please refresh.') console.log("New content is available; please refresh.")
} else { } else {
// At this point, everything has been precached. // At this point, everything has been precached.
// It's the perfect time to display a // It's the perfect time to display a
// "Content is cached for offline use." message. // "Content is cached for offline use." message.
console.log('Content is cached for offline use.') console.log("Content is cached for offline use.")
} }
} }
} }
} }
}) })
.catch(error => { .catch(error => {
console.error('Error during service worker registration:', error) console.error("Error during service worker registration:", error)
}) })
} }
@ -88,7 +88,7 @@ function checkValidServiceWorker (swUrl) {
// Ensure service worker exists, and that we really are getting a JS file. // Ensure service worker exists, and that we really are getting a JS file.
if ( if (
response.status === 404 || response.status === 404 ||
response.headers.get('content-type').indexOf('javascript') === -1 response.headers.get("content-type").indexOf("javascript") === -1
) { ) {
// No service worker found. Probably a different app. Reload the page. // No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => { navigator.serviceWorker.ready.then(registration => {
@ -103,13 +103,13 @@ function checkValidServiceWorker (swUrl) {
}) })
.catch(() => { .catch(() => {
console.log( console.log(
'No internet connection found. App is running in offline mode.' "No internet connection found. App is running in offline mode."
) )
}) })
} }
export function unregister() { export function unregister() {
if ('serviceWorker' in navigator) { if ("serviceWorker" in navigator) {
navigator.serviceWorker.ready.then(registration => { navigator.serviceWorker.ready.then(registration => {
registration.unregister() registration.unregister()
}) })

View File

@ -1,10 +1,10 @@
import React from "react" import React, { Component, ReactNode } from "react"
import { Route, Switch } from "react-router-dom" import { Route as RouteComponent, Switch } from "react-router-dom"
import { redirects, routes } from "./routes" import { Redirect, redirects, Route, routes } from "./routes"
export default class Routes extends React.Component { export default class Routes extends Component {
public render() { public render(): ReactNode {
return ( return (
<Switch> <Switch>
{this.renderRoutes()} {this.renderRoutes()}
@ -13,9 +13,9 @@ export default class Routes extends React.Component {
) )
} }
private renderRoutes() { private renderRoutes(): ReactNode[] {
return routes.map(route => ( return routes.map((route: Route) => (
<Route <RouteComponent
key={route.name} key={route.name}
exact={route.exact} exact={route.exact}
path={route.path} path={route.path}
@ -24,9 +24,9 @@ export default class Routes extends React.Component {
)) ))
} }
private renderRedirects() { private renderRedirects(): ReactNode[] {
return redirects.map(route => ( return redirects.map((route: Redirect) => (
<Route key={route.path} path={route.path} render={route.func} /> <RouteComponent key={route.path} path={route.path} render={route.func} />
)) ))
} }
} }

View File

@ -1,7 +1,20 @@
import { ComponentClass, ReactNode } from "react"
import Contact from "../screens/Contact" import Contact from "../screens/Contact"
import Home from "../screens/Home" import Home from "../screens/Home"
import Projects from "../screens/Projects" import Projects from "../screens/Projects"
export type Route = {
component: ComponentClass
exact: boolean
name: string
path: string
}
export type Redirect = {
func: () => ReactNode
path: string
}
export const routes = [ export const routes = [
{ {
component: Home, component: Home,
@ -25,7 +38,7 @@ export const routes = [
export const redirects = [ export const redirects = [
{ {
func: () => { func: (): ReactNode => {
window.location.replace("https://linkedin.com/in/mitchelljfsimon") window.location.replace("https://linkedin.com/in/mitchelljfsimon")
return null return null
}, },

View File

@ -1,10 +1,10 @@
import React from "react" import React, { PureComponent, ReactNode } from "react"
import linkedIn from "../../images/In-2C-128px-TM.png" import linkedIn from "../../images/In-2C-128px-TM.png"
import "./index.css" import "./index.css"
export default class Contact extends React.PureComponent { export default class Contact extends PureComponent {
public render() { public render(): ReactNode {
return ( return (
<div className="contact-container"> <div className="contact-container">
<p>m@mjfs.us</p> <p>m@mjfs.us</p>

View File

@ -1,4 +1,4 @@
import * as React from "react" import React, { PureComponent, ReactNode } from "react"
import Job from "../../components/Job" import Job from "../../components/Job"
import jobsData from "../../data/jobs.json" import jobsData from "../../data/jobs.json"
@ -11,15 +11,15 @@ type JobData = {
bullets: string[] bullets: string[]
} }
export default class Experience extends React.PureComponent { export default class Experience extends PureComponent {
public render() { public render(): ReactNode {
return ( return (
<div className="experience-container">{this.renderJobs(jobsData)}</div> <div className="experience-container">{this.renderJobs(jobsData)}</div>
) )
} }
private renderJobs(jobs: JobData[]) { private renderJobs(jobs: JobData[]): ReactNode[] {
return jobs.map(job => ( return jobs.map((job: JobData) => (
<Job <Job
key={job.title} key={job.title}
title={job.title} title={job.title}

View File

@ -1,10 +1,10 @@
import * as React from "react" import React, { PureComponent, ReactNode } from "react"
import profile from "../../images/profile.jpg" import profile from "../../images/profile.jpg"
import "./index.css" import "./index.css"
export default class Home extends React.PureComponent { export default class Home extends PureComponent {
public render() { public render(): ReactNode {
return ( return (
<div className="home-container"> <div className="home-container">
<img src={profile} alt="Profile" /> <img src={profile} alt="Profile" />

View File

@ -1,5 +1,4 @@
// @flow import React, { PureComponent, ReactNode } from "react"
import * as React from "react"
import Project from "../../components/Project" import Project from "../../components/Project"
@ -20,8 +19,8 @@ type ProjectData = {
description: string description: string
} }
export default class Projects extends React.PureComponent { export default class Projects extends PureComponent {
public render() { public render(): ReactNode {
return ( return (
<div className="projects-container"> <div className="projects-container">
{this.renderProjects(projectsData)} {this.renderProjects(projectsData)}
@ -29,8 +28,8 @@ export default class Projects extends React.PureComponent {
) )
} }
private renderProjects(projects: ProjectData[]) { private renderProjects(projects: ProjectData[]): ReactNode[] {
return projects.map(project => ( return projects.map((project: ProjectData) => (
<Project <Project
key={project.title} key={project.title}
title={project.title} title={project.title}

View File

@ -20,7 +20,9 @@
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"noEmit": true "noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true
}, },
"exclude": [ "exclude": [
"node_modules", "node_modules",

View File

@ -2,8 +2,21 @@
"extends": ["tslint:latest", "tslint-config-prettier"], "extends": ["tslint:latest", "tslint-config-prettier"],
"defaultSeverity": "warning", "defaultSeverity": "warning",
"rules": { "rules": {
"no-any": true,
"no-unsafe-any": true,
"no-magic-numbers": true,
"no-console": true,
"cyclomatic-complexity": [true, 10],
"typedef": [
true,
"call-signature",
"arrow-call-signature",
"parameter",
"arrow-parameter",
"property-declaration",
"member-variable-declaration"
],
"semicolon": false, "semicolon": false,
"resolve-json-module": true,
"interface-over-type-literal": false "interface-over-type-literal": false
}, },
"linterOptions": { "linterOptions": {