From b9ee14fe5b185f3533326a15f05056cc8bd685ce Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Wed, 22 Feb 2023 14:47:51 +0900
Subject: fix:
 MkUserSelectDialog/search-by-username-and-hostでローカルユーザーを絞って検索できない問題を修正
 (#9943)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: MkUserSelectDialog/search-by-username-and-hostでローカルユーザーを絞って検索できない問題を修正
Fix #9627

* update CHANGELOG.md

* clean up

* search-by-username-and-host大改造
---
 packages/frontend/src/components/MkUserSelectDialog.vue | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'packages/frontend/src/components/MkUserSelectDialog.vue')

diff --git a/packages/frontend/src/components/MkUserSelectDialog.vue b/packages/frontend/src/components/MkUserSelectDialog.vue
index 981ae56e6c..4ce8c08512 100644
--- a/packages/frontend/src/components/MkUserSelectDialog.vue
+++ b/packages/frontend/src/components/MkUserSelectDialog.vue
@@ -16,7 +16,7 @@
 					<template #label>{{ i18n.ts.username }}</template>
 					<template #prefix>@</template>
 				</MkInput>
-				<MkInput v-model="host" @update:model-value="search">
+				<MkInput v-model="host" @update:model-value="search" :datalist="[hostname]">
 					<template #label>{{ i18n.ts.host }}</template>
 					<template #prefix>@</template>
 				</MkInput>
@@ -61,6 +61,7 @@ import * as os from '@/os';
 import { defaultStore } from '@/store';
 import { i18n } from '@/i18n';
 import { $i } from '@/account';
+import { hostname } from '@/config';
 
 const emit = defineEmits<{
 	(ev: 'ok', selected: misskey.entities.UserDetailed): void;
@@ -115,7 +116,7 @@ onMounted(() => {
 	os.api('users/show', {
 		userIds: defaultStore.state.recentlyUsedUsers,
 	}).then(users => {
-		if (props.includeSelf) {
+		if (props.includeSelf && users.find(x => $i ? x.id === $i.id : true) == null) {
 			recentUsers = [$i, ...users];
 		} else {
 			recentUsers = users;
-- 
cgit v1.2.3-freya


From 0fb9c372ddec7d5284d6402625cbaffc9ac7eb0b Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Wed, 22 Feb 2023 15:28:17 +0900
Subject: lint

---
 packages/frontend/.eslintrc.js                     |  1 +
 .../src/components/MkAbuseReportWindow.vue         |  2 +-
 .../frontend/src/components/MkAutocomplete.vue     |  2 +-
 packages/frontend/src/components/MkCaptcha.vue     |  2 +-
 packages/frontend/src/components/MkMediaList.vue   |  8 +++---
 .../src/components/MkNotificationSettingWindow.vue |  2 +-
 packages/frontend/src/components/MkPagination.vue  |  2 +-
 packages/frontend/src/components/MkPostForm.vue    |  8 +++---
 .../frontend/src/components/MkUserSelectDialog.vue |  2 +-
 .../src/components/global/MkCustomEmoji.vue        |  4 +--
 .../src/components/global/MkPageHeader.vue         |  8 +++---
 packages/frontend/src/pages/admin/_header_.vue     |  2 +-
 packages/frontend/src/pages/auth.vue               | 15 ++++++-----
 packages/frontend/src/pages/settings/profile.vue   | 10 ++++----
 packages/frontend/src/pizzax.ts                    | 30 +++++++++++-----------
 packages/frontend/src/scripts/get-note-menu.ts     |  6 ++---
 packages/frontend/src/scripts/hpml/index.ts        |  2 +-
 packages/frontend/src/scripts/hpml/type-checker.ts |  4 +--
 packages/frontend/src/scripts/scroll.ts            | 16 ++++++------
 packages/frontend/src/theme-store.ts               |  6 ++---
 packages/frontend/src/ui/classic.vue               |  2 +-
 packages/sw/src/scripts/get-user-name.ts           |  6 +----
 22 files changed, 69 insertions(+), 71 deletions(-)

(limited to 'packages/frontend/src/components/MkUserSelectDialog.vue')

diff --git a/packages/frontend/.eslintrc.js b/packages/frontend/.eslintrc.js
index 6c3bfb5a6e..e8e0e57d2a 100644
--- a/packages/frontend/.eslintrc.js
+++ b/packages/frontend/.eslintrc.js
@@ -55,6 +55,7 @@ module.exports = {
 		'vue/multi-word-component-names': 'warn',
 		'vue/require-v-for-key': 'warn',
 		'vue/no-unused-components': 'warn',
+		'vue/no-unused-vars': 'warn',
 		'vue/valid-v-for': 'warn',
 		'vue/return-in-computed-property': 'warn',
 		'vue/no-setup-props-destructure': 'warn',
diff --git a/packages/frontend/src/components/MkAbuseReportWindow.vue b/packages/frontend/src/components/MkAbuseReportWindow.vue
index a76a1e0f54..9f2bf99338 100644
--- a/packages/frontend/src/components/MkAbuseReportWindow.vue
+++ b/packages/frontend/src/components/MkAbuseReportWindow.vue
@@ -43,7 +43,7 @@ const emit = defineEmits<{
 }>();
 
 const uiWindow = shallowRef<InstanceType<typeof MkWindow>>();
-const comment = ref(props.initialComment || '');
+const comment = ref(props.initialComment ?? '');
 
 function send() {
 	os.apiWithDialog('users/report-abuse', {
diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue
index 7e5432434f..663c57623d 100644
--- a/packages/frontend/src/components/MkAutocomplete.vue
+++ b/packages/frontend/src/components/MkAutocomplete.vue
@@ -209,7 +209,7 @@ function exec() {
 		}
 	} else if (props.type === 'hashtag') {
 		if (!props.q || props.q === '') {
-			hashtags.value = JSON.parse(miLocalStorage.getItem('hashtags') || '[]');
+			hashtags.value = JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]');
 			fetching.value = false;
 		} else {
 			const cacheKey = `autocomplete:hashtag:${props.q}`;
diff --git a/packages/frontend/src/components/MkCaptcha.vue b/packages/frontend/src/components/MkCaptcha.vue
index 8db2e54e88..c72cc2ab1b 100644
--- a/packages/frontend/src/components/MkCaptcha.vue
+++ b/packages/frontend/src/components/MkCaptcha.vue
@@ -69,7 +69,7 @@ const captcha = computed<Captcha>(() => window[variable.value] || {} as unknown
 if (loaded) {
 	available.value = true;
 } else {
-	(document.getElementById(scriptId.value) || document.head.appendChild(Object.assign(document.createElement('script'), {
+	(document.getElementById(scriptId.value) ?? document.head.appendChild(Object.assign(document.createElement('script'), {
 		async: true,
 		id: scriptId.value,
 		src: src.value,
diff --git a/packages/frontend/src/components/MkMediaList.vue b/packages/frontend/src/components/MkMediaList.vue
index e957d8f56c..a12bb78e35 100644
--- a/packages/frontend/src/components/MkMediaList.vue
+++ b/packages/frontend/src/components/MkMediaList.vue
@@ -45,8 +45,8 @@ onMounted(() => {
 					src: media.url,
 					w: media.properties.width,
 					h: media.properties.height,
-					alt: media.comment || media.name,
-					comment: media.comment || media.name,
+					alt: media.comment ?? media.name,
+					comment: media.comment ?? media.name,
 				};
 				if (media.properties.orientation != null && media.properties.orientation >= 5) {
 					[item.w, item.h] = [item.h, item.w];
@@ -90,8 +90,8 @@ onMounted(() => {
 			[itemData.w, itemData.h] = [itemData.h, itemData.w];
 		}
 		itemData.msrc = file.thumbnailUrl;
-		itemData.alt = file.comment || file.name;
-		itemData.comment = file.comment || file.name;
+		itemData.alt = file.comment ?? file.name;
+		itemData.comment = file.comment ?? file.name;
 		itemData.thumbCropped = true;
 	});
 
diff --git a/packages/frontend/src/components/MkNotificationSettingWindow.vue b/packages/frontend/src/components/MkNotificationSettingWindow.vue
index e303403872..2d8d30e337 100644
--- a/packages/frontend/src/components/MkNotificationSettingWindow.vue
+++ b/packages/frontend/src/components/MkNotificationSettingWindow.vue
@@ -54,7 +54,7 @@ const props = withDefaults(defineProps<{
 	showGlobalToggle: true,
 });
 
-let includingTypes = $computed(() => props.includingTypes || []);
+let includingTypes = $computed(() => props.includingTypes ?? []);
 
 const dialog = $shallowRef<InstanceType<typeof MkModalWindow>>();
 
diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue
index 224a42cdc2..84ba94361e 100644
--- a/packages/frontend/src/components/MkPagination.vue
+++ b/packages/frontend/src/components/MkPagination.vue
@@ -104,7 +104,7 @@ const {
 	enableInfiniteScroll,
 } = defaultStore.reactiveState;
 
-const contentEl = $computed(() => props.pagination.pageEl || rootEl);
+const contentEl = $computed(() => props.pagination.pageEl ?? rootEl);
 const scrollableElement = $computed(() => getScrollContainer(contentEl));
 
 // 先頭が表示されているかどうかを検出
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 2bcc58e8f7..54512aa4d8 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -154,7 +154,7 @@ let autocomplete = $ref(null);
 let draghover = $ref(false);
 let quoteId = $ref(null);
 let hasNotSpecifiedMentions = $ref(false);
-let recentHashtags = $ref(JSON.parse(miLocalStorage.getItem('hashtags') || '[]'));
+let recentHashtags = $ref(JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]'));
 let imeText = $ref('');
 
 const draftKey = $computed((): string => {
@@ -533,7 +533,7 @@ function onDrop(ev): void {
 }
 
 function saveDraft() {
-	const draftData = JSON.parse(miLocalStorage.getItem('drafts') || '{}');
+	const draftData = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}');
 
 	draftData[draftKey] = {
 		updatedAt: new Date(),
@@ -642,7 +642,7 @@ async function post(ev?: MouseEvent) {
 			emit('posted');
 			if (postData.text && postData.text !== '') {
 				const hashtags_ = mfm.parse(postData.text).filter(x => x.type === 'hashtag').map(x => x.props.hashtag);
-				const history = JSON.parse(miLocalStorage.getItem('hashtags') || '[]') as string[];
+				const history = JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]') as string[];
 				miLocalStorage.setItem('hashtags', JSON.stringify(unique(hashtags_.concat(history))));
 			}
 			posting = false;
@@ -746,7 +746,7 @@ onMounted(() => {
 	nextTick(() => {
 		// 書きかけの投稿を復元
 		if (!props.instant && !props.mention && !props.specified) {
-			const draft = JSON.parse(miLocalStorage.getItem('drafts') || '{}')[draftKey];
+			const draft = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}')[draftKey];
 			if (draft) {
 				text = draft.data.text;
 				useCw = draft.data.useCw;
diff --git a/packages/frontend/src/components/MkUserSelectDialog.vue b/packages/frontend/src/components/MkUserSelectDialog.vue
index 4ce8c08512..dc78bbf42d 100644
--- a/packages/frontend/src/components/MkUserSelectDialog.vue
+++ b/packages/frontend/src/components/MkUserSelectDialog.vue
@@ -16,7 +16,7 @@
 					<template #label>{{ i18n.ts.username }}</template>
 					<template #prefix>@</template>
 				</MkInput>
-				<MkInput v-model="host" @update:model-value="search" :datalist="[hostname]">
+				<MkInput v-model="host" :datalist="[hostname]" @update:model-value="search">
 					<template #label>{{ i18n.ts.host }}</template>
 					<template #prefix>@</template>
 				</MkInput>
diff --git a/packages/frontend/src/components/global/MkCustomEmoji.vue b/packages/frontend/src/components/global/MkCustomEmoji.vue
index e6dedd0354..82aad44c1f 100644
--- a/packages/frontend/src/components/global/MkCustomEmoji.vue
+++ b/packages/frontend/src/components/global/MkCustomEmoji.vue
@@ -24,7 +24,7 @@ const rawUrl = computed(() => {
 		return props.url;
 	}
 	if (props.host == null && !customEmojiName.value.includes('@')) {
-		return customEmojis.value.find(x => x.name === customEmojiName.value)?.url || null;
+		return customEmojis.value.find(x => x.name === customEmojiName.value)?.url ?? null;
 	}
 	return props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`;
 });
@@ -32,7 +32,7 @@ const rawUrl = computed(() => {
 const url = computed(() =>
 	defaultStore.reactiveState.disableShowingAnimatedImages.value && rawUrl.value
 		? getStaticImageUrl(rawUrl.value)
-		: rawUrl.value
+		: rawUrl.value,
 );
 
 const alt = computed(() => `:${customEmojiName.value}:`);
diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue
index 98233b02e0..a4e25bbe1a 100644
--- a/packages/frontend/src/components/global/MkPageHeader.vue
+++ b/packages/frontend/src/components/global/MkPageHeader.vue
@@ -2,9 +2,9 @@
 <div v-if="show" ref="el" :class="[$style.root]" :style="{ background: bg }">
 	<div :class="[$style.upper, { [$style.slim]: narrow, [$style.thin]: thin_ }]">
 		<div v-if="!thin_ && narrow && props.displayMyAvatar && $i" class="_button" :class="$style.buttonsLeft" @click="openAccountMenu">
-			<MkAvatar :class="$style.avatar" :user="$i" />
+			<MkAvatar :class="$style.avatar" :user="$i"/>
 		</div>
-		<div v-else-if="!thin_ && narrow && !hideTitle" :class="$style.buttonsLeft" />
+		<div v-else-if="!thin_ && narrow && !hideTitle" :class="$style.buttonsLeft"/>
 
 		<template v-if="metadata">
 			<div v-if="!hideTitle" :class="$style.titleContainer" @click="top">
@@ -36,11 +36,11 @@
 <script lang="ts" setup>
 import { onMounted, onUnmounted, ref, inject } from 'vue';
 import tinycolor from 'tinycolor2';
+import XTabs, { Tab } from './MkPageHeader.tabs.vue';
 import { scrollToTop } from '@/scripts/scroll';
 import { globalEvents } from '@/events';
 import { injectPageMetadata } from '@/scripts/page-metadata';
 import { $i, openAccountMenu as openAccountMenu_ } from '@/account';
-import XTabs, { Tab } from './MkPageHeader.tabs.vue';
 
 const props = withDefaults(defineProps<{
 	tabs?: Tab[];
@@ -96,7 +96,7 @@ function onTabClick(): void {
 }
 
 const calcBg = () => {
-	const rawBg = metadata?.bg || 'var(--bg)';
+	const rawBg = metadata?.bg ?? 'var(--bg)';
 	const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
 	tinyBg.setAlpha(0.85);
 	bg.value = tinyBg.toRgbString();
diff --git a/packages/frontend/src/pages/admin/_header_.vue b/packages/frontend/src/pages/admin/_header_.vue
index 599b16e465..372c63ff4c 100644
--- a/packages/frontend/src/pages/admin/_header_.vue
+++ b/packages/frontend/src/pages/admin/_header_.vue
@@ -113,7 +113,7 @@ function onTabClick(tab: Tab, ev: MouseEvent): void {
 }
 
 const calcBg = () => {
-	const rawBg = metadata?.bg || 'var(--bg)';
+	const rawBg = metadata?.bg ?? 'var(--bg)';
 	const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
 	tinyBg.setAlpha(0.85);
 	bg.value = tinyBg.toRgbString();
diff --git a/packages/frontend/src/pages/auth.vue b/packages/frontend/src/pages/auth.vue
index 50afffc460..4f8afb9ea2 100644
--- a/packages/frontend/src/pages/auth.vue
+++ b/packages/frontend/src/pages/auth.vue
@@ -1,12 +1,12 @@
 <template>
 <MkStickyContainer>
-	<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs" /></template>
+	<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
 	<MkSpacer :content-max="500">
 		<div v-if="state == 'fetch-session-error'">
 			<p>{{ i18n.ts.somethingHappened }}</p>
 		</div>
 		<div v-else-if="$i && !session">
-			<MkLoading />
+			<MkLoading/>
 		</div>
 		<div v-else-if="$i && session">
 			<XForm
@@ -21,15 +21,16 @@
 			</div>
 			<div v-if="state == 'accepted' && session">
 				<h1>{{ session.app.isAuthorized ? $t('already-authorized') : i18n.ts.allowed }}</h1>
-				<p v-if="session.app.callbackUrl">{{ i18n.ts._auth.callback }}
-					<MkEllipsis />
+				<p v-if="session.app.callbackUrl">
+					{{ i18n.ts._auth.callback }}
+					<MkEllipsis/>
 				</p>
 				<p v-if="!session.app.callbackUrl">{{ i18n.ts._auth.pleaseGoBack }}</p>
 			</div>
 		</div>
 		<div v-else>
 			<p :class="$style.loginMessage">{{ i18n.ts._auth.pleaseLogin }}</p>
-			<MkSignin @login="onLogin" />
+			<MkSignin @login="onLogin"/>
 		</div>
 	</MkSpacer>
 </MkStickyContainer>
@@ -37,12 +38,12 @@
 
 <script lang="ts" setup>
 import { onMounted } from 'vue';
+import { AuthSession } from 'misskey-js/built/entities';
 import XForm from './auth.form.vue';
 import MkSignin from '@/components/MkSignin.vue';
 import * as os from '@/os';
 import { $i, login } from '@/account';
 import { definePageMetadata } from '@/scripts/page-metadata';
-import { AuthSession } from 'misskey-js/built/entities';
 import { i18n } from '@/i18n';
 
 const props = defineProps<{
@@ -82,7 +83,7 @@ onMounted(async () => {
 		} else {
 			state = 'waiting';
 		}
-	} catch (e) {
+	} catch (err) {
 		state = 'fetch-session-error';
 	}
 });
diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue
index a492a82588..41563c441f 100644
--- a/packages/frontend/src/pages/settings/profile.vue
+++ b/packages/frontend/src/pages/settings/profile.vue
@@ -124,11 +124,11 @@ function saveFields() {
 
 function save() {
 	os.apiWithDialog('i/update', {
-		name: profile.name || null,
-		description: profile.description || null,
-		location: profile.location || null,
-		birthday: profile.birthday || null,
-		lang: profile.lang || null,
+		name: profile.name ?? null,
+		description: profile.description ?? null,
+		location: profile.location ?? null,
+		birthday: profile.birthday ?? null,
+		lang: profile.lang ?? null,
 		isBot: !!profile.isBot,
 		isCat: !!profile.isCat,
 		showTimelineReplies: !!profile.showTimelineReplies,
diff --git a/packages/frontend/src/pizzax.ts b/packages/frontend/src/pizzax.ts
index 2ca89b7351..2616a8a1d5 100644
--- a/packages/frontend/src/pizzax.ts
+++ b/packages/frontend/src/pizzax.ts
@@ -48,8 +48,8 @@ export class Storage<T extends StateDef> {
 	// 簡易的にキューイングして占有ロックとする
 	private currentIdbJob: Promise<any> = Promise.resolve();
 	private addIdbSetJob<T>(job: () => Promise<T>) {
-		const promise = this.currentIdbJob.then(job, e => {
-			console.error('Pizzax failed to save data to idb!', e);
+		const promise = this.currentIdbJob.then(job, err => {
+			console.error('Pizzax failed to save data to idb!', err);
 			return job();
 		});
 		this.currentIdbJob = promise;
@@ -130,22 +130,22 @@ export class Storage<T extends StateDef> {
 					await defaultStore.ready;
 
 					api('i/registry/get-all', { scope: ['client', this.key] })
-					.then(kvs => {
-						const cache: Partial<T> = {};
-						for (const [k, v] of Object.entries(this.def) as [keyof T, T[keyof T]['default']][]) {
-							if (v.where === 'account') {
-								if (Object.prototype.hasOwnProperty.call(kvs, k)) {
-									this.reactiveState[k].value = this.state[k] = (kvs as Partial<T>)[k];
-									cache[k] = (kvs as Partial<T>)[k];
-								} else {
-									this.reactiveState[k].value = this.state[k] = v.default;
+						.then(kvs => {
+							const cache: Partial<T> = {};
+							for (const [k, v] of Object.entries(this.def) as [keyof T, T[keyof T]['default']][]) {
+								if (v.where === 'account') {
+									if (Object.prototype.hasOwnProperty.call(kvs, k)) {
+										this.reactiveState[k].value = this.state[k] = (kvs as Partial<T>)[k];
+										cache[k] = (kvs as Partial<T>)[k];
+									} else {
+										this.reactiveState[k].value = this.state[k] = v.default;
+									}
 								}
 							}
-						}
 	
-						return set(this.registryCacheKeyName, cache);
-					})
-					.then(() => resolve());
+							return set(this.registryCacheKeyName, cache);
+						})
+						.then(() => resolve());
 				}, 1);
 			} else {
 				resolve();
diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts
index 48b740f4c3..c54be43d19 100644
--- a/packages/frontend/src/scripts/get-note-menu.ts
+++ b/packages/frontend/src/scripts/get-note-menu.ts
@@ -240,7 +240,7 @@ export function getNoteMenu(props: {
 				icon: 'ti ti-external-link',
 				text: i18n.ts.showOnRemote,
 				action: () => {
-					window.open(appearNote.url || appearNote.uri, '_blank');
+					window.open(appearNote.url ?? appearNote.uri, '_blank');
 				},
 			} : undefined,
 			{
@@ -302,7 +302,7 @@ export function getNoteMenu(props: {
 					icon: 'ti ti-exclamation-circle',
 					text: i18n.ts.reportAbuse,
 					action: () => {
-						const u = appearNote.url || appearNote.uri || `${url}/notes/${appearNote.id}`;
+						const u = appearNote.url ?? appearNote.uri ?? `${url}/notes/${appearNote.id}`;
 						os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), {
 							user: appearNote.user,
 							initialComment: `Note: ${u}\n-----\n`,
@@ -344,7 +344,7 @@ export function getNoteMenu(props: {
 			icon: 'ti ti-external-link',
 			text: i18n.ts.showOnRemote,
 			action: () => {
-				window.open(appearNote.url || appearNote.uri, '_blank');
+				window.open(appearNote.url ?? appearNote.uri, '_blank');
 			},
 		} : undefined]
 			.filter(x => x !== undefined);
diff --git a/packages/frontend/src/scripts/hpml/index.ts b/packages/frontend/src/scripts/hpml/index.ts
index 5c07a08315..587c6a36c8 100644
--- a/packages/frontend/src/scripts/hpml/index.ts
+++ b/packages/frontend/src/scripts/hpml/index.ts
@@ -58,7 +58,7 @@ export class HpmlScope {
 
 	constructor(layerdStates: HpmlScope['layerdStates'], name?: HpmlScope['name']) {
 		this.layerdStates = layerdStates;
-		this.name = name || 'anonymous';
+		this.name = name ?? 'anonymous';
 	}
 
 	@autobind
diff --git a/packages/frontend/src/scripts/hpml/type-checker.ts b/packages/frontend/src/scripts/hpml/type-checker.ts
index 24c9ed8bcb..692826fc90 100644
--- a/packages/frontend/src/scripts/hpml/type-checker.ts
+++ b/packages/frontend/src/scripts/hpml/type-checker.ts
@@ -63,7 +63,7 @@ export class HpmlTypeChecker {
 
 	@autobind
 	public getExpectedType(v: Expr, slot: number): Type {
-		const def = funcDefs[v.type || ''];
+		const def = funcDefs[v.type ?? ''];
 		if (def == null) {
 			throw new Error('Unknown type: ' + v.type);
 		}
@@ -107,7 +107,7 @@ export class HpmlTypeChecker {
 				return pageVar.type;
 			}
 
-			const envVar = envVarsDef[v.value || ''];
+			const envVar = envVarsDef[v.value ?? ''];
 			if (envVar !== undefined) {
 				return envVar;
 			}
diff --git a/packages/frontend/src/scripts/scroll.ts b/packages/frontend/src/scripts/scroll.ts
index e3d9dc00c2..a002f02b5a 100644
--- a/packages/frontend/src/scripts/scroll.ts
+++ b/packages/frontend/src/scripts/scroll.ts
@@ -10,7 +10,7 @@ export function getScrollContainer(el: HTMLElement | null): HTMLElement | null {
 	}
 }
 
-export function getStickyTop(el: HTMLElement, container: HTMLElement | null = null, top: number = 0) {
+export function getStickyTop(el: HTMLElement, container: HTMLElement | null = null, top = 0) {
 	if (!el.parentElement) return top;
 	const data = el.dataset.stickyContainerHeaderHeight;
 	const newTop = data ? Number(data) + top : top;
@@ -23,14 +23,14 @@ export function getScrollPosition(el: HTMLElement | null): number {
 	return container == null ? window.scrollY : container.scrollTop;
 }
 
-export function onScrollTop(el: HTMLElement, cb: () => unknown, tolerance: number = 1, once: boolean = false) {
+export function onScrollTop(el: HTMLElement, cb: () => unknown, tolerance = 1, once = false) {
 	// とりあえず評価してみる
 	if (isTopVisible(el)) {
 		cb();
 		if (once) return null;
 	}
 
-	const container = getScrollContainer(el) || window;
+	const container = getScrollContainer(el) ?? window;
 
 	const onScroll = ev => {
 		if (!document.body.contains(el)) return;
@@ -45,7 +45,7 @@ export function onScrollTop(el: HTMLElement, cb: () => unknown, tolerance: numbe
 	return removeListener;
 }
 
-export function onScrollBottom(el: HTMLElement, cb: () => unknown, tolerance: number = 1, once: boolean = false) {
+export function onScrollBottom(el: HTMLElement, cb: () => unknown, tolerance = 1, once = false) {
 	const container = getScrollContainer(el);
 
 	// とりあえず評価してみる
@@ -54,7 +54,7 @@ export function onScrollBottom(el: HTMLElement, cb: () => unknown, tolerance: nu
 		if (once) return null;
 	}
 
-	const containerOrWindow = container || window;
+	const containerOrWindow = container ?? window;
 	const onScroll = ev => {
 		if (!document.body.contains(el)) return;
 		if (isBottomVisible(el, 1, container)) {
@@ -104,12 +104,12 @@ export function scrollToBottom(
 	} else {
 		window.scroll({
 			top: (el.scrollHeight - window.innerHeight + getStickyTop(el, container) + (window.innerWidth <= 500 ? 96 : 0)) || 0,
-			...options
+			...options,
 		});
 	}
 }
 
-export function isTopVisible(el: HTMLElement, tolerance: number = 1): boolean {
+export function isTopVisible(el: HTMLElement, tolerance = 1): boolean {
 	const scrollTop = getScrollPosition(el);
 	return scrollTop <= tolerance;
 }
@@ -124,6 +124,6 @@ export function getBodyScrollHeight() {
 	return Math.max(
 		document.body.scrollHeight, document.documentElement.scrollHeight,
 		document.body.offsetHeight, document.documentElement.offsetHeight,
-		document.body.clientHeight, document.documentElement.clientHeight
+		document.body.clientHeight, document.documentElement.clientHeight,
 	);
 }
diff --git a/packages/frontend/src/theme-store.ts b/packages/frontend/src/theme-store.ts
index aa1244665b..580c7da007 100644
--- a/packages/frontend/src/theme-store.ts
+++ b/packages/frontend/src/theme-store.ts
@@ -1,13 +1,13 @@
-import { api } from '@/os';
-import { $i } from '@/account';
 import { Theme } from './scripts/theme';
 import { miLocalStorage } from './local-storage';
+import { api } from '@/os';
+import { $i } from '@/account';
 
 const lsCacheKey = $i ? `themes:${$i.id}` as const : null;
 
 export function getThemes(): Theme[] {
 	if ($i == null) return [];
-	return JSON.parse(miLocalStorage.getItem(lsCacheKey!) || '[]');
+	return JSON.parse(miLocalStorage.getItem(lsCacheKey!) ?? '[]');
 }
 
 export async function fetchThemes(): Promise<void> {
diff --git a/packages/frontend/src/ui/classic.vue b/packages/frontend/src/ui/classic.vue
index 92997ffb66..a359463d9b 100644
--- a/packages/frontend/src/ui/classic.vue
+++ b/packages/frontend/src/ui/classic.vue
@@ -125,7 +125,7 @@ function onAiClick(ev) {
 
 if (window.innerWidth < 1024) {
 	const currentUI = miLocalStorage.getItem('ui');
-	miLocalStorage.setItem('ui_temp', currentUI || 'default');
+	miLocalStorage.setItem('ui_temp', currentUI ?? 'default');
 	miLocalStorage.setItem('ui', 'default');
 	location.reload();
 }
diff --git a/packages/sw/src/scripts/get-user-name.ts b/packages/sw/src/scripts/get-user-name.ts
index ccc38c298e..4daf203e06 100644
--- a/packages/sw/src/scripts/get-user-name.ts
+++ b/packages/sw/src/scripts/get-user-name.ts
@@ -1,7 +1,3 @@
 export default function(user: { name?: string | null, username: string }): string {
-	// Show username if name is empty.
-	// XXX: typescript-eslint has no configuration to allow using `||` against string.
-	// https://github.com/typescript-eslint/typescript-eslint/issues/4906
-	// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
-	return user.name || user.username;
+	return user.name === '' ? user.username : user.name ?? user.username;
 }
-- 
cgit v1.2.3-freya

