run prettier

This commit is contained in:
Pig Fang 2020-05-16 22:05:16 +08:00
parent ec24dff36a
commit c48583dd6d
38 changed files with 127 additions and 113 deletions

View File

@ -13,6 +13,7 @@
"dev": "webpack-dev-server",
"build": "webpack --mode=production -p --progress",
"lint": "eslint --ext=ts -f=beauty .",
"fmt": "prettier --write 'resources/assets/**/*.{ts,tsx}'",
"test": "jest"
},
"dependencies": {
@ -201,6 +202,7 @@
],
"coveragePathIgnorePatterns": [
"/node_modules/",
"<rootDir>/resources/assets/styles",
"<rootDir>/resources/assets/tests/setup",
"<rootDir>/resources/assets/tests/utils",
"<rootDir>/resources/assets/tests/scripts/cli/stdio"

View File

@ -5,7 +5,7 @@ interface Props {
onClick: React.MouseEventHandler<HTMLAnchorElement>
}
const ButtonEdit: React.FC<Props> = props => (
const ButtonEdit: React.FC<Props> = (props) => (
<a href="#" title={props.title} className="ml-2" onClick={props.onClick}>
<i className="fas fa-edit"></i>
</a>

View File

@ -14,7 +14,7 @@ export function on(event: string | symbol, listener: CallableFunction) {
}
export function emit(event: string | symbol, payload?: unknown) {
bus.get(event)?.forEach(listener => listener(payload))
bus.get(event)?.forEach((listener) => listener(payload))
}
blessing.event = { on, emit }

View File

@ -3,7 +3,7 @@ function handler() {
/* istanbul ignore else */
if (header) {
window.addEventListener('scroll', () => {
if (window.scrollY >= window.innerHeight * 2 / 3) {
if (window.scrollY >= (window.innerHeight * 2) / 3) {
header.classList.remove('transparent')
} else {
header.classList.add('transparent')

View File

@ -1,6 +1,6 @@
export function t(key: string, parameters = Object.create(null)): string {
const segments = key.split('.')
let temp = (blessing.i18n) as {
let temp = blessing.i18n as {
[k: string]: string | { [k: string]: string }
}
let result = ''
@ -17,8 +17,9 @@ export function t(key: string, parameters = Object.create(null)): string {
}
}
Object.keys(parameters)
.forEach(slot => (result = result.replace(`:${slot}`, parameters[slot])))
Object.keys(parameters).forEach(
(slot) => (result = result.replace(`:${slot}`, parameters[slot])),
)
return result
}

View File

@ -9,9 +9,10 @@ declare let __webpack_public_path__: string
const url = new URL(blessing.base_url)
url.port = '8080'
__webpack_public_path__ = process.env.NODE_ENV === 'development'
? url.toString()
: `${blessing.base_url}/app/`
__webpack_public_path__ =
process.env.NODE_ENV === 'development'
? url.toString()
: `${blessing.base_url}/app/`
// @ts-ignore
window.$ = window.jQuery = $ // eslint-disable-line

View File

@ -58,7 +58,7 @@ export async function walkFetch(request: Request): Promise<any> {
} = body
return {
code: 1,
message: Object.keys(errors).map(field => errors[field][0])[0],
message: Object.keys(errors).map((field) => errors[field][0])[0],
}
} else if (response.status === 419) {
showModal({
@ -106,9 +106,7 @@ export function get<T = any>(url: string, params = empty): Promise<T> {
const qs = new URLSearchParams(params)
return walkFetch(
new Request(`${blessing.base_url}${url}?${qs}`, init),
)
return walkFetch(new Request(`${blessing.base_url}${url}?${qs}`, init))
}
function nonGet<T = any>(method: string, url: string, data: any): Promise<T> {

View File

@ -17,7 +17,7 @@ function checkPixel(
/* istanbul ignore next */
export function isAlex(texture: string): Promise<boolean> {
return new Promise(resolve => {
return new Promise((resolve) => {
const image = new Image()
image.src = texture
image.onload = () => {

View File

@ -15,7 +15,7 @@ export const ToastContainer: React.FC = () => {
useEffect(() => {
const off1 = emitter.on(TOAST_EVENT, (toast: QueueElement) => {
setQueue(queue => {
setQueue((queue) => {
queue.push(toast)
return queue.slice()
})
@ -29,7 +29,7 @@ export const ToastContainer: React.FC = () => {
}, [])
const handleClose = (id: string) => {
setQueue(queue => queue.filter(el => el.id !== id))
setQueue((queue) => queue.filter((el) => el.id !== id))
}
return (

View File

@ -7,14 +7,13 @@ export function registerNavbarPicker(
picker: HTMLDivElement,
init: string,
): void {
const color$ = fromEvent(picker, 'click')
.pipe(
map(event => (event.target as HTMLElement)),
filter(
(element): element is HTMLInputElement => element.tagName === 'INPUT',
),
map(element => element.value),
)
const color$ = fromEvent(picker, 'click').pipe(
map((event) => event.target as HTMLElement),
filter(
(element): element is HTMLInputElement => element.tagName === 'INPUT',
),
map((element) => element.value),
)
merge(of(init), color$)
.pipe(pairwise())
@ -22,9 +21,8 @@ export function registerNavbarPicker(
navbar.classList.replace(`navbar-${previous}`, `navbar-${current}`)
})
const [light$, dark$] = partition(
color$,
color => ['light', 'warning', 'white', 'orange', 'lime'].includes(color),
const [light$, dark$] = partition(color$, (color) =>
['light', 'warning', 'white', 'orange', 'lime'].includes(color),
)
light$.subscribe(() => {
// DO NOT use `classList.replace`.
@ -47,18 +45,18 @@ if (navbar && picker) {
export function registerSidebarPicker(
sidebar: HTMLElement,
{ dark, light }: { dark: HTMLDivElement, light: HTMLDivElement },
{ dark, light }: { dark: HTMLDivElement; light: HTMLDivElement },
init: string,
): void {
const color$ = merge(
fromEvent(dark, 'click'),
fromEvent(light, 'click'),
).pipe(
map(event => (event.target as HTMLElement)),
map((event) => event.target as HTMLElement),
filter(
(element): element is HTMLInputElement => element.tagName === 'INPUT',
),
map(element => element.value),
map((element) => element.value),
)
merge(of(init), color$)
@ -69,10 +67,12 @@ export function registerSidebarPicker(
}
const sidebar = document.querySelector<HTMLElement>('.main-sidebar')
const darkPicker = document
.querySelector<HTMLDivElement>('#sidebar-dark-picker')
const lightPicker = document
.querySelector<HTMLDivElement>('#sidebar-light-picker')
const darkPicker = document.querySelector<HTMLDivElement>(
'#sidebar-dark-picker',
)
const lightPicker = document.querySelector<HTMLDivElement>(
'#sidebar-light-picker',
)
/* istanbul ignore next */
if (sidebar && darkPicker && lightPicker) {
registerSidebarPicker(

View File

@ -7,7 +7,9 @@ export default async function handler(event: MouseEvent) {
button.disabled = true
const text = button.textContent
button.innerHTML = `<i class="fas fa-spinner fa-spin"></i> ${t('admin.downloading')}`
button.innerHTML = `<i class="fas fa-spinner fa-spin"></i> ${t(
'admin.downloading',
)}`
const { code, message }: ResponseBody = await post('/admin/update/download')
button.textContent = text

View File

@ -18,7 +18,7 @@ const BindPlayers: React.FC = () => {
const response = await fetch.get<fetch.ResponseBody<Player[]>>(
'/user/player/list',
)
const players = response.data.map(player => player.name)
const players = response.data.map((player) => player.name)
setPlayers(players)
setSelected(players[0])
setIsLoading(false)
@ -52,7 +52,7 @@ const BindPlayers: React.FC = () => {
<>
<p>{t('user.bindExistedPlayer')}</p>
<div className="mb-3">
{players.map(player => (
{players.map((player) => (
<label className="d-block mb-1">
<input
key={player}
@ -73,7 +73,7 @@ const BindPlayers: React.FC = () => {
type="text"
className="form-control mb-3"
placeholder={t('general.player.player-name')}
onChange={e => setSelected(e.target.value)}
onChange={(e) => setSelected(e.target.value)}
/>
</>
)}

View File

@ -11,7 +11,7 @@ interface Props {
isAlex: boolean
}
const Previewer: React.FC<Props> = props => {
const Previewer: React.FC<Props> = (props) => {
const container = useMount('#previewer')
const skin = props.skin ? `${blessing.base_url}/textures/${props.skin}` : ''

View File

@ -20,7 +20,7 @@ export default async function setAsAvatar(tid: number) {
toast.success(message)
document
.querySelectorAll<HTMLImageElement>('[alt="User Image"]')
.forEach(el => (el.src += `?${new Date().getTime()}`))
.forEach((el) => (el.src += `?${new Date().getTime()}`))
} else {
toast.error(message)
}

View File

@ -10,7 +10,7 @@ interface Props {
onClick: React.MouseEventHandler<HTMLButtonElement>
}
const SignButton: React.FC<Props> = props => {
const SignButton: React.FC<Props> = (props) => {
const { lastSign, signGap, canSignAfterZero } = props
const remainingTime = scoreUtils.remainingTime(
lastSign,

View File

@ -8,7 +8,7 @@ interface Props {
onClose(): void
}
const ModalCreate: React.FC<Props> = props => {
const ModalCreate: React.FC<Props> = (props) => {
const [name, setName] = useState('')
const [url, setUrl] = useState('')

View File

@ -10,7 +10,7 @@ interface Props {
onDelete: React.MouseEventHandler<HTMLButtonElement>
}
const Row: React.FC<Props> = props => {
const Row: React.FC<Props> = (props) => {
const { app } = props
return (

View File

@ -18,7 +18,7 @@ interface Props {
onClose(): void
}
const ModalAddPlayer: React.FC<Props> = props => {
const ModalAddPlayer: React.FC<Props> = (props) => {
const [name, setName] = useState('')
const handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {

View File

@ -8,7 +8,7 @@ interface Props {
onClose(): void
}
const ModalReset: React.FC<Props> = props => {
const ModalReset: React.FC<Props> = (props) => {
const [skin, setSkin] = useState(false)
const [cape, setCape] = useState(false)

View File

@ -13,12 +13,12 @@ interface Props {
isAlex: boolean
}
const Previewer: React.FC<Props> = props => {
const Previewer: React.FC<Props> = (props) => {
const [is3d, setIs3d] = useState(true)
const container = useMount('#previewer')
const switchMode = () => setIs3d(is => !is)
const switchMode = () => setIs3d((is) => !is)
const switcher = (
<button className="btn btn-default" onClick={switchMode}>
@ -40,7 +40,7 @@ const Previewer: React.FC<Props> = props => {
{switcher}
</Viewer2d>
),
container
container,
)
}

View File

@ -7,10 +7,10 @@ export default async function handler(event: Event) {
const form = event.target as HTMLFormElement
const password: string = form.password.value
const { code, message }: ResponseBody = await post(
'/user/profile?action=delete',
{ password },
)
const {
code,
message,
}: ResponseBody = await post('/user/profile?action=delete', { password })
await showModal({ mode: 'alert', text: message })
if (code === 0) {

View File

@ -8,10 +8,13 @@ export default async function handler(event: Event) {
const email: string = form.email.value
const password: string = form.password.value
const { code, message }: ResponseBody = await post(
'/user/profile?action=email',
{ new_email: email, password },
)
const {
code,
message,
}: ResponseBody = await post('/user/profile?action=email', {
new_email: email,
password,
})
await showModal({ mode: 'alert', text: message })
if (code === 0) {
window.location.href = `${blessing.base_url}/auth/login`

View File

@ -16,6 +16,7 @@ nicknameForm?.addEventListener('submit', nicknameFormHandler)
const emailForm = document.querySelector<HTMLFormElement>('#change-email')
emailForm?.addEventListener('submit', emailFormHandler)
const deleteAccountForm = document
.querySelector<HTMLFormElement>('#modal-delete-account')
const deleteAccountForm = document.querySelector<HTMLFormElement>(
'#modal-delete-account',
)
deleteAccountForm?.addEventListener('submit', deleteAccountFormHandler)

View File

@ -7,15 +7,16 @@ export default async function handler(event: Event) {
const form = event.target as HTMLFormElement
const nickname: string = form.nickname.value
const { code, message }: ResponseBody = await post(
'/user/profile?action=nickname', { new_nickname: nickname },
)
const {
code,
message,
}: ResponseBody = await post('/user/profile?action=nickname', {
new_nickname: nickname,
})
showModal({ mode: 'alert', text: message })
if (code === 0) {
document
.querySelectorAll('[data-mark="nickname"]')
.forEach(el => {
el.textContent = nickname
})
document.querySelectorAll('[data-mark="nickname"]').forEach((el) => {
el.textContent = nickname
})
}
}

View File

@ -16,10 +16,13 @@ export default async function handler(event: Event) {
return
}
const { code, message }: ResponseBody = await post(
'/user/profile?action=password',
{ current_password: oldPassword, new_password: newPassword },
)
const {
code,
message,
}: ResponseBody = await post('/user/profile?action=password', {
current_password: oldPassword,
new_password: newPassword,
})
await showModal({ mode: 'alert', text: message })
if (code === 0) {
window.location.href = `${blessing.base_url}/auth/login`

View File

@ -15,7 +15,7 @@ export default async function resetAvatar() {
toast.success(message)
document
.querySelectorAll<HTMLImageElement>('[alt="User Image"]')
.forEach(el => {
.forEach((el) => {
el.src += `?${new Date().getTime()}`
})
}

View File

@ -40,8 +40,8 @@ const NotificationsList: React.FC = () => {
</>
),
})
setNotifications(notifications =>
notifications.filter(notification => notification.id !== id),
setNotifications((notifications) =>
notifications.filter((notification) => notification.id !== id),
)
}
@ -59,7 +59,7 @@ const NotificationsList: React.FC = () => {
</a>
<div className="dropdown-menu dropdown-menu-lg dropdown-menu-right">
{hasUnread ? (
notifications.map(notification => (
notifications.map((notification) => (
<>
<a
href="#"

View File

@ -1,8 +1,6 @@
/* eslint-disable max-params */
/* eslint-disable max-classes-per-file */
import {
PlayerObject, SkinObject, CapeObject,
} from 'skinview3d'
import { PlayerObject, SkinObject, CapeObject } from 'skinview3d'
export class SkinViewer {
disposed: boolean

View File

@ -6,9 +6,7 @@ jest.mock('@/scripts/net')
jest.mock('@/scripts/notify')
test('log out', async () => {
showModal
.mockRejectedValueOnce(null)
.mockResolvedValueOnce({ value: '' })
showModal.mockRejectedValueOnce(null).mockResolvedValueOnce({ value: '' })
post.mockResolvedValue({ message: '' })
await logout()

View File

@ -31,13 +31,12 @@ test('the GET method', async () => {
})
test('the POST method', async () => {
window.fetch = jest.fn()
.mockResolvedValue({
ok: true,
json: () => Promise.resolve({}),
headers: new Map([['Content-Type', 'application/json']]),
clone: () => ({}),
})
window.fetch = jest.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({}),
headers: new Map([['Content-Type', 'application/json']]),
clone: () => ({}),
})
const meta = document.createElement('meta')
meta.name = 'csrf-token'
@ -115,7 +114,8 @@ test('the DELETE method', () => {
test('low level fetch', async () => {
const json = jest.fn().mockResolvedValue({})
window.fetch = jest.fn()
window.fetch = jest
.fn()
.mockRejectedValueOnce(new Error('network'))
.mockResolvedValueOnce({
ok: false,
@ -186,7 +186,8 @@ test('low level fetch', async () => {
})
test('process backend errors', async () => {
window.fetch = jest.fn()
window.fetch = jest
.fn()
.mockResolvedValueOnce({
status: 422,
headers: new Map([['Content-Type', 'application/json']]),
@ -255,7 +256,8 @@ test('process backend errors', async () => {
expect(showModal).toBeCalledWith({
mode: 'alert',
title: t('general.fatalError'),
dangerousHTML: 'fake exception<br><details>[1] k.php#L2<br>[2] v.php#L3</details>',
dangerousHTML:
'fake exception<br><details>[1] k.php#L2<br>[2] v.php#L3</details>',
type: 'danger',
okButtonType: 'outline-light',
})

View File

@ -1,5 +1,8 @@
import { ModalOptions, ModalResult } from '../../src/components/Modal'
import { Toast } from '../../src/scripts/toast'
export const showModal = {} as jest.Mock<Promise<ModalResult>, [ModalOptions | void]>
export const showModal = {} as jest.Mock<
Promise<ModalResult>,
[ModalOptions | void]
>
export const toast = {} as Toast

View File

@ -33,12 +33,16 @@ test('preview sidebar color', () => {
const darkPicker = document.createElement('div')
darkPicker.innerHTML = `
<label><input type="radio" name="sidebar" value="dark-cyan"></label>`
const darkCyan = darkPicker.querySelector<HTMLInputElement>('[value="dark-cyan"]')!
const darkCyan = darkPicker.querySelector<HTMLInputElement>(
'[value="dark-cyan"]',
)!
const lightPicker = document.createElement('div')
lightPicker.innerHTML = `
<label><input type="radio" name="sidebar" value="light-cyan"></label>`
const lightCyan = lightPicker.querySelector<HTMLInputElement>('[value="light-cyan"]')!
const lightCyan = lightPicker.querySelector<HTMLInputElement>(
'[value="light-cyan"]',
)!
registerSidebarPicker(
sidebar,

View File

@ -7,7 +7,8 @@ jest.mock('@/scripts/notify')
jest.mock('@/scripts/net')
test('click button', async () => {
post.mockResolvedValueOnce({ code: 1, message: 'failed' })
post
.mockResolvedValueOnce({ code: 1, message: 'failed' })
.mockResolvedValue({ code: 0, message: 'ok' })
const button = document.createElement('button')

View File

@ -23,10 +23,9 @@ test('delete account', async () => {
const event = new Event('submit')
form.dispatchEvent(event)
await flushPromises()
expect(post).toBeCalledWith(
'/user/profile?action=delete',
{ password: 'abc' },
)
expect(post).toBeCalledWith('/user/profile?action=delete', {
password: 'abc',
})
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'w' })
form.dispatchEvent(event)

View File

@ -29,10 +29,10 @@ test('change email', async () => {
const event = new Event('submit')
form.dispatchEvent(event)
await flushPromises()
expect(post).toBeCalledWith(
'/user/profile?action=email',
{ new_email: 'a@b.c', password: 'abc' },
)
expect(post).toBeCalledWith('/user/profile?action=email', {
new_email: 'a@b.c',
password: 'abc',
})
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'w' })
form.dispatchEvent(event)

View File

@ -24,10 +24,9 @@ test('change nickname', async () => {
const event = new Event('submit')
form.dispatchEvent(event)
await flushPromises()
expect(post).toBeCalledWith(
'/user/profile?action=nickname',
{ new_nickname: 'nickname' },
)
expect(post).toBeCalledWith('/user/profile?action=nickname', {
new_nickname: 'nickname',
})
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'w' })
form.dispatchEvent(event)

View File

@ -42,10 +42,10 @@ test('change password', async () => {
confirm.value = '1'
form.dispatchEvent(event)
await flushPromises()
expect(post).toBeCalledWith(
'/user/profile?action=password',
{ current_password: '1', new_password: '1' },
)
expect(post).toBeCalledWith('/user/profile?action=password', {
current_password: '1',
new_password: '1',
})
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'w' })
form.dispatchEvent(event)

View File

@ -6,9 +6,7 @@ jest.mock('@/scripts/notify')
jest.mock('@/scripts/net')
test('reset avatar', async () => {
showModal
.mockRejectedValueOnce(null)
.mockResolvedValue({ value: '' })
showModal.mockRejectedValueOnce(null).mockResolvedValue({ value: '' })
post.mockResolvedValue({ message: 'ok' })
document.body.innerHTML = '<img alt="User Image" src="a">'