1
0
mirror of https://github.com/uetchy/namae.git synced 2025-08-20 09:58:13 +09:00

chore: add eslint rules

This commit is contained in:
2019-12-24 01:57:07 +09:00
parent 934486d64f
commit 1fd9332bdc
35 changed files with 381 additions and 404 deletions

View File

@@ -5,7 +5,7 @@ import {FaTwitter, FaGithubAlt} from 'react-icons/fa';
import {ExternalLink} from './Links';
export default function Footer() {
const Footer: React.FC = () => {
const {t} = useTranslation();
return (
@@ -51,7 +51,8 @@ export default function Footer() {
</Box>
</Container>
);
}
};
export default Footer;
const Container = styled.div`
display: flex;

View File

@@ -15,19 +15,19 @@ const Form: React.FC<{onQuery: (query: string) => void}> = ({onQuery}) => {
const {t} = useTranslation();
// set input value
function onInputChange(e: React.FormEvent<HTMLInputElement>) {
function onInputChange(e: React.FormEvent<HTMLInputElement>): void {
const value = e.currentTarget.value;
setInputValue(value);
}
// clear input form and focus on it
function onLogoClick(e: React.MouseEvent<HTMLDivElement>) {
function onLogoClick(): void {
setInputValue('');
inputRef.current!.focus();
inputRef.current?.focus();
}
// invoke when user clicked one of the suggested items
function onSuggestionCompleted(name: string) {
function onSuggestionCompleted(name: string): void {
setInputValue(name);
setSuggested(true);
}

View File

@@ -1,6 +1,6 @@
import React from 'react';
export const SpectrumIcon = () => (
export const SpectrumIcon: React.FC = () => (
<svg
width="1em"
height="1em"
@@ -13,7 +13,7 @@ export const SpectrumIcon = () => (
</svg>
);
export const NowIcon = () => (
export const NowIcon: React.FC = () => (
<svg
width="1em"
height="1em"
@@ -28,7 +28,7 @@ export const NowIcon = () => (
</svg>
);
export const NetlifyIcon = () => (
export const NetlifyIcon: React.FC = () => (
<svg
width="1em"
height="1em"

View File

@@ -9,47 +9,47 @@ import {mobile} from '../util/css';
type Modifier = (word: string) => string;
const maximumCount = 3;
const modifiers: Modifier[] = [
(word) => `${capitalize(word)}ify`,
(word) => `lib${lower(word)}`,
(word) => `Omni${capitalize(word)}`,
(word) => `${capitalize(word)}Lab`,
(word) => `${capitalize(word)}Kit`,
(word) => `Open${capitalize(word)}`,
(word) => `${capitalize(word)}box`,
(word) => `Insta${lower(word)}`,
(word) => `${capitalize(word)}Hub`,
(word) => `Cloud${capitalize(word)}`,
(word) => `quick${lower(word)}`,
(word) => `fast${lower(word)}`,
(word) => `super-${lower(word)}`,
(word) => `Hyper${capitalize(word)}`,
(word) => `${capitalize(word)}Go`,
(word) => `${lower(word)}-io`,
(word) => `Go${capitalize(word)}`,
(word) => `${capitalize(word)}X`,
(word) => `${capitalize(word)}time`,
(word) => `${capitalize(word)}flow`,
(word) => `${capitalize(word)}ful`,
(word) => `${capitalize(word)}ery`,
(word) => `${lower(word)}ly`,
(word) => `${lower(word)}joy`,
(word) => `${capitalize(word)}Hunt`,
(word) => `${capitalize(word)}gram`,
(word) => `${capitalize(word)}base`,
(word) => `${capitalize(word)}API`,
(word) => `${capitalize(word)}note`,
(word) => `In${capitalize(word)}`,
(word) => `Uni${lower(word)}`,
(word) => `${capitalize(word)}`,
];
function lower(word: string) {
function lower(word: string): string {
return word.toLowerCase();
}
function shuffleArray(array: any[]) {
const maximumCount = 3;
const modifiers: Modifier[] = [
(word): string => `${capitalize(word)}ify`,
(word): string => `lib${lower(word)}`,
(word): string => `Omni${capitalize(word)}`,
(word): string => `${capitalize(word)}Lab`,
(word): string => `${capitalize(word)}Kit`,
(word): string => `Open${capitalize(word)}`,
(word): string => `${capitalize(word)}box`,
(word): string => `Insta${lower(word)}`,
(word): string => `${capitalize(word)}Hub`,
(word): string => `Cloud${capitalize(word)}`,
(word): string => `quick${lower(word)}`,
(word): string => `fast${lower(word)}`,
(word): string => `super-${lower(word)}`,
(word): string => `Hyper${capitalize(word)}`,
(word): string => `${capitalize(word)}Go`,
(word): string => `${lower(word)}-io`,
(word): string => `Go${capitalize(word)}`,
(word): string => `${capitalize(word)}X`,
(word): string => `${capitalize(word)}time`,
(word): string => `${capitalize(word)}flow`,
(word): string => `${capitalize(word)}ful`,
(word): string => `${capitalize(word)}ery`,
(word): string => `${lower(word)}ly`,
(word): string => `${lower(word)}joy`,
(word): string => `${capitalize(word)}Hunt`,
(word): string => `${capitalize(word)}gram`,
(word): string => `${capitalize(word)}base`,
(word): string => `${capitalize(word)}API`,
(word): string => `${capitalize(word)}note`,
(word): string => `In${capitalize(word)}`,
(word): string => `Uni${lower(word)}`,
(word): string => `${capitalize(word)}`,
];
function shuffleArray<T>(array: T[]): T[] {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
const temp = array[i];
@@ -59,15 +59,15 @@ function shuffleArray(array: any[]) {
return array;
}
function sampleFromArray(array: any[], maximum: number) {
function sampleFromArray<T>(array: T[], maximum: number): T[] {
return shuffleArray(array).slice(0, maximum);
}
function modifyWord(word: string) {
function modifyWord(word: string): string {
return modifiers[Math.floor(Math.random() * modifiers.length)](word);
}
function fillArray(array: any[], filler: string, maximum: number) {
function fillArray<T>(array: T[], filler: string, maximum: number): T[] {
const deficit = maximum - array.length;
if (deficit > 0) {
array = [...array, ...Array(deficit).fill(filler)];
@@ -75,7 +75,7 @@ function fillArray(array: any[], filler: string, maximum: number) {
return array;
}
async function findSynonyms(word: string) {
async function findSynonyms(word: string): Promise<string[]> {
try {
const response = await fetch(
`https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&dt=ss&ie=UTF-8&oe=UTF-8&dj=1&q=${encodeURIComponent(
@@ -92,7 +92,7 @@ async function findSynonyms(word: string) {
[] as string[],
),
),
).filter((word) => !word.match(/[\s-]/));
).filter((word) => !/[\s-]/.exec(word));
return synonyms;
} catch (err) {
return [];
@@ -107,7 +107,7 @@ const Suggestion: React.FC<{
const synonymRef = useRef<string[]>([]);
const [bestWords, setBestWords] = useState<string[]>([]);
function shuffle() {
function shuffle(): void {
const best = fillArray(
sampleFromArray(synonymRef.current, maximumCount),
query,
@@ -116,12 +116,12 @@ const Suggestion: React.FC<{
setBestWords(best);
}
function applyQuery(name: string) {
function applyQuery(name: string): void {
onSubmit(name);
}
useEffect(() => {
const fn = async () => {
const fn = async (): Promise<void> => {
if (query && query.length > 0) {
const synonyms = await findSynonyms(query);
synonymRef.current = synonyms;
@@ -142,7 +142,7 @@ const Suggestion: React.FC<{
<Items>
{bestWords &&
bestWords.map((name) => (
<Item key={name} onClick={() => applyQuery(name)}>
<Item key={name} onClick={(): void => applyQuery(name)}>
{name}
</Item>
))}

View File

@@ -23,7 +23,7 @@ import {DiRust, DiHeroku} from 'react-icons/di';
import {SpectrumIcon, NowIcon, NetlifyIcon} from './Icons';
import {mobile} from '../util/css';
export default function Welcome() {
const Welcome: React.FC = () => {
const {t} = useTranslation();
return (
@@ -96,7 +96,8 @@ export default function Welcome() {
</List>
</Container>
);
}
};
export default Welcome;
const Container = styled.div`
padding-bottom: 40px;

View File

@@ -231,6 +231,7 @@ class ErrorBoundary extends React.Component<
return {hasError: true, message: error.message};
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
componentDidCatch(error: Error, errorInfo: any) {
if (error instanceof APIError || error instanceof NotFoundError) {
return;

View File

@@ -15,8 +15,9 @@ const isLocalhost = Boolean(
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/,
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/.exec(
window.location.hostname,
),
);
@@ -25,7 +26,87 @@ type Config = {
onUpdate?: (registration: ServiceWorkerRegistration) => void;
};
export function register(config?: Config) {
function registerValidSW(swUrl: string, config?: Config): void {
navigator.serviceWorker
.register(swUrl)
.then((registration) => {
registration.onupdatefound = (): void => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = (): void => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.',
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch((error) => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl: string, config?: Config): void {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then((response) => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && !contentType.includes('javascript'))
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.',
);
});
}
export function unregister(): void {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then((registration) => {
registration.unregister();
});
}
}
export function register(config?: Config): void {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(
@@ -61,83 +142,3 @@ export function register(config?: Config) {
});
}
}
function registerValidSW(swUrl: string, config?: Config) {
navigator.serviceWorker
.register(swUrl)
.then((registration) => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.',
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch((error) => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl: string, config?: Config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then((response) => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.',
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then((registration) => {
registration.unregister();
});
}
}

View File

@@ -3,14 +3,14 @@ import * as Sentry from '@sentry/browser';
const isProduction = process.env.NODE_ENV !== 'development';
export function initGA() {
export function initGA(): void {
if (isProduction) {
ReactGA.initialize('UA-28919359-15');
ReactGA.pageview(window.location.pathname + window.location.search);
}
}
export function sendQueryStatistics(queryLength: number) {
export function sendQueryStatistics(queryLength: number): void {
if (isProduction) {
ReactGA.event({
category: 'Search',
@@ -20,7 +20,7 @@ export function sendQueryStatistics(queryLength: number) {
}
}
export function initSentry() {
export function initSentry(): void {
if (isProduction) {
Sentry.init({
dsn: 'https://7ab2df74aead499b950ebef190cc40b7@sentry.io/1759299',
@@ -28,7 +28,13 @@ export function initSentry() {
}
}
export function sendError(error: Error, errorInfo: any): Promise<string> {
export function sendError(
error: Error,
errorInfo: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
},
): Promise<string> {
return new Promise((resolve) => {
if (isProduction) {
Sentry.withScope((scope) => {

View File

@@ -1,10 +1,10 @@
interface CrispWindow extends Window {
$crisp: any[];
$crisp: unknown[];
CRISP_WEBSITE_ID: string;
}
declare var window: CrispWindow;
declare let window: CrispWindow;
export function initCrisp() {
export function initCrisp(): void {
window.$crisp = [];
window.CRISP_WEBSITE_ID = '92b2e096-6892-47dc-bf4a-057bad52d82e';
const s = document.createElement('script');

View File

@@ -12,7 +12,7 @@ export function useDeferredState<T>(
setResponse(innerValue);
}, duration);
return () => {
return (): void => {
clearTimeout(fn);
};
}, [duration, innerValue]);

View File

@@ -2,7 +2,7 @@ interface CustomNavigator extends Navigator {
standalone?: boolean;
}
export function isStandalone() {
export function isStandalone(): boolean {
const navigator: CustomNavigator = window.navigator;
return 'standalone' in navigator && navigator.standalone;
return 'standalone' in navigator && navigator.standalone === true;
}

View File

@@ -15,7 +15,7 @@ const Container = styled.div`
align-items: center;
`;
const Fallback = () => (
const Fallback: React.FC = () => (
<Container>
<BarLoader />
</Container>

View File

@@ -1,4 +1,4 @@
export function capitalize(text: string) {
export function capitalize(text: string): string {
if (text.length === 0) return '';
return text[0].toUpperCase() + text.slice(1).toLowerCase();
}