Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor sw #10579

Merged
merged 34 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
92e3af6
refactor(sw): remove dead code
okayurisotto Apr 8, 2023
b10f2d8
refactor(sw): remove dead code
okayurisotto Apr 8, 2023
ec283ad
refactor(sw): remove dead code
okayurisotto Apr 8, 2023
f61005d
refactor(sw): remove dead code
okayurisotto Apr 8, 2023
5d23c32
refactor(sw): remove dead code
okayurisotto Apr 8, 2023
c1cb9cc
refactor(sw): remove dead code
okayurisotto Apr 8, 2023
52c8643
refactor(sw): 冗長な部分を変更
okayurisotto Apr 8, 2023
514aa49
refactor(sw): 使われていない煩雑な機能を削除
okayurisotto Apr 8, 2023
401f50a
refactor(sw): remove dead code
okayurisotto Apr 8, 2023
4dd1529
refactor(sw): URL文字列の作成に`URL`を使うように
okayurisotto Apr 8, 2023
0affea5
refactor(sw): 型アサーションの削除とそれに伴い露呈したエラーへの対処
okayurisotto Apr 8, 2023
aa71a19
refactor(sw): `append` -> `set` in `URLSearchParams`
okayurisotto Apr 8, 2023
cefe73c
refactor(sw): `any`の削除とそれに伴い露呈したエラーへの対処
okayurisotto Apr 8, 2023
ebbb6df
refactor(sw): 型アサーションの削除とそれに伴い露呈したエラーへの対処
okayurisotto Apr 8, 2023
13f53a3
refactor(sw): i18n loading
okayurisotto Apr 8, 2023
8d163d9
refactor(sw): 型推論がうまくできる書き方に変更
okayurisotto Apr 8, 2023
46d6452
refactor(sw): クエリ文字列の作成に`URLSearchParams`を使うように
okayurisotto Apr 8, 2023
278d54d
refactor(sw): `findClient`
okayurisotto Apr 8, 2023
2bde9d5
refactor(sw): `openClient`における`any`や`as`の書き換え
okayurisotto Apr 8, 2023
d09aae6
refactor(sw): `openPost`における`any`の書き換え
okayurisotto Apr 8, 2023
3fc3808
Merge branch 'develop' into refactor-sw
tamaina Apr 11, 2023
46a7b53
refactor(sw): `let` -> `const`
okayurisotto Apr 11, 2023
3778659
refactor(sw): `any` -> `unknown`
okayurisotto Apr 11, 2023
2557f90
cleanup(sw): import
okayurisotto Apr 11, 2023
9ed974e
cleanup(sw)
okayurisotto Apr 11, 2023
00312b5
cleanup(sw): `?.`
okayurisotto Apr 11, 2023
30af3e6
cleanup(sw/.eslintrc.js)
okayurisotto Apr 11, 2023
5b5c3ce
refactor(sw): `@typescript-eslint/explicit-function-return-type`
okayurisotto Apr 11, 2023
986757a
refactor(sw): `@typescript-eslint/no-unused-vars`
okayurisotto Apr 11, 2023
629c282
refactor(sw): どうしようもないところに`eslint-disable-next-line`を
okayurisotto Apr 11, 2023
f10bddf
refactor(sw): `import/no-default-export`
okayurisotto Apr 11, 2023
c440804
Merge branch 'develop' into refactor-sw
okayurisotto Apr 11, 2023
98577e3
update operations.ts
tamaina Apr 11, 2023
6c97849
throw new Error
tamaina Apr 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions packages/sw/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
module.exports = {
root: true,
env: {
"node": false
node: false,
},
parserOptions: {
"parser": "@typescript-eslint/parser",
parser: '@typescript-eslint/parser',
tsconfigRootDir: __dirname,
project: ['./tsconfig.json'],
},
extends: [
"../shared/.eslintrc.js",
],
extends: ['../shared/.eslintrc.js'],
globals: {
"require": false,
"_DEV_": false,
"_LANGS_": false,
"_VERSION_": false,
"_ENV_": false,
"_PERF_PREFIX_": false,
}
}
require: false,
_DEV_: false,
_LANGS_: false,
_VERSION_: false,
_ENV_: false,
_PERF_PREFIX_: false,
},
};
1 change: 1 addition & 0 deletions packages/sw/src/@types/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type FIXME = any;

declare const _LANGS_: string[][];
Expand Down
14 changes: 0 additions & 14 deletions packages/sw/src/filters/user.ts

This file was deleted.

32 changes: 14 additions & 18 deletions packages/sw/src/scripts/create-notification.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
/*
* Notification manager for SW
*/
import { swLang } from '@/scripts/lang';
import type { BadgeNames, PushNotificationDataMap } from '@/types';
import { char2fileName } from '@/scripts/twemoji-base';
import { cli } from '@/scripts/operations';
import { BadgeNames, PushNotificationDataMap } from '@/types';
import getUserName from '@/scripts/get-user-name';
import { I18n } from '@/scripts/i18n';
import { getAccountFromId } from '@/scripts/get-account-from-id';
import { char2fileName } from '@/scripts/twemoji-base';
import * as url from '@/scripts/url';
import { swLang } from '@/scripts/lang';
import { getUserName } from '@/scripts/get-user-name';

const closeNotificationsByTags = async (tags: string[]) => {
const closeNotificationsByTags = async (tags: string[]): Promise<void> => {
for (const n of (await Promise.all(tags.map(tag => globalThis.registration.getNotifications({ tag })))).flat()) {
n.close();
}
};

const iconUrl = (name: BadgeNames) => `/static-assets/tabler-badges/${name}.png`;
const iconUrl = (name: BadgeNames): string => `/static-assets/tabler-badges/${name}.png`;
/* How to add a new badge:
* 1. Find the icon and download png from https://tabler-icons.io/
* 2. vips resize ~/Downloads/icon-name.png vipswork.png 0.4; vips scRGB2BW vipswork.png ~/icon-name.png"[compression=9,strip]"; rm vipswork.png;
Expand All @@ -25,7 +23,7 @@ const iconUrl = (name: BadgeNames) => `/static-assets/tabler-badges/${name}.png`
* 5. Add `badge: iconUrl('icon-name'),`
*/

export async function createNotification<K extends keyof PushNotificationDataMap>(data: PushNotificationDataMap[K]) {
export async function createNotification<K extends keyof PushNotificationDataMap>(data: PushNotificationDataMap[K]): Promise<void> {
const n = await composeNotification(data);

if (n) {
Expand All @@ -37,8 +35,7 @@ export async function createNotification<K extends keyof PushNotificationDataMap
}

async function composeNotification(data: PushNotificationDataMap[keyof PushNotificationDataMap]): Promise<[string, NotificationOptions] | null> {
if (!swLang.i18n) swLang.fetchLocale();
const i18n = await swLang.i18n as I18n<any>;
const i18n = await (swLang.i18n ?? swLang.fetchLocale());
const { t } = i18n;
switch (data.type) {
/*
Expand Down Expand Up @@ -139,16 +136,16 @@ async function composeNotification(data: PushNotificationDataMap[keyof PushNotif
if (reaction.startsWith(':')) {
// カスタム絵文字の場合
const name = reaction.substring(1, reaction.length - 1);
badge = `${origin}/emoji/${name}.webp?${url.query({
badge: '1',
})}`;
const badgeUrl = new URL(`/emoji/${name}.webp`, origin);
badgeUrl.searchParams.set('badge', '1');
badge = badgeUrl.href;
reaction = name.split('@')[0];
} else {
// Unicode絵文字の場合
badge = `/twemoji-badge/${char2fileName(reaction)}.png`;
}

if (badge ? await fetch(badge).then(res => res.status !== 200).catch(() => true) : true) {
if (await fetch(badge).then(res => res.status !== 200).catch(() => true)) {
badge = iconUrl('plus');
}

Expand Down Expand Up @@ -226,10 +223,9 @@ async function composeNotification(data: PushNotificationDataMap[keyof PushNotif
}
}

export async function createEmptyNotification() {
export async function createEmptyNotification(): Promise<void> {
return new Promise<void>(async res => {
if (!swLang.i18n) swLang.fetchLocale();
const i18n = await swLang.i18n as I18n<any>;
const i18n = await (swLang.i18n ?? swLang.fetchLocale());
const { t } = i18n;

await globalThis.registration.showNotification(
Expand Down
9 changes: 6 additions & 3 deletions packages/sw/src/scripts/get-account-from-id.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { get } from 'idb-keyval';

export async function getAccountFromId(id: string) {
const accounts = await get('accounts') as { token: string; id: string; }[];
if (!accounts) console.log('Accounts are not recorded');
export async function getAccountFromId(id: string): Promise<{ token: string; id: string } | void> {
const accounts = await get<{ token: string; id: string }[]>('accounts');
if (!accounts) {
console.log('Accounts are not recorded');
return;
}
return accounts.find(e => e.id === id);
}
2 changes: 1 addition & 1 deletion packages/sw/src/scripts/get-user-name.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export default function(user: { name?: string | null, username: string }): string {
export function getUserName(user: { name?: string | null; username: string }): string {
return user.name === '' ? user.username : user.name ?? user.username;
}
7 changes: 5 additions & 2 deletions packages/sw/src/scripts/i18n.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export class I18n<T extends Record<string, any>> {
export type Locale = { [key: string]: string | Locale };

export class I18n<T extends Locale = Locale> {
public ts: T;

constructor(locale: T) {
Expand All @@ -13,7 +15,8 @@ export class I18n<T extends Record<string, any>> {
// なるべくこのメソッド使うよりもlocale直接参照の方がvueのキャッシュ効いてパフォーマンスが良いかも
public t(key: string, args?: Record<string, string>): string {
try {
let str = key.split('.').reduce((o, i) => o[i], this.ts) as unknown as string;
let str = key.split('.').reduce<Locale | Locale[keyof Locale]>((o, i) => o[i], this.ts);
if (typeof str !== 'string') throw new Error();

if (args) {
for (const [k, v] of Object.entries(args)) {
Expand Down
18 changes: 9 additions & 9 deletions packages/sw/src/scripts/lang.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Language manager for SW
*/
import { get, set } from 'idb-keyval';
import { I18n } from '@/scripts/i18n';
import { I18n, type Locale } from '@/scripts/i18n';

class SwLang {
public cacheName = `mk-cache-${_VERSION_}`;
Expand All @@ -12,33 +12,33 @@ class SwLang {
return prelang;
});

public setLang(newLang: string) {
public setLang(newLang: string): Promise<I18n<Locale>> {
this.lang = Promise.resolve(newLang);
set('lang', newLang);
return this.fetchLocale();
}

public i18n: Promise<I18n<any>> | null = null;
public i18n: Promise<I18n> | null = null;

public fetchLocale() {
return this.i18n = this._fetch();
public fetchLocale(): Promise<I18n<Locale>> {
return (this.i18n = this._fetch());
}

private async _fetch() {
private async _fetch(): Promise<I18n<Locale>> {
// Service Workerは何度も起動しそのたびにlocaleを読み込むので、CacheStorageを使う
const localeUrl = `/assets/locales/${await this.lang}.${_VERSION_}.json`;
let localeRes = await caches.match(localeUrl);

// _DEV_がtrueの場合は常に最新化
if (!localeRes || _DEV_) {
localeRes = await fetch(localeUrl);
const clone = localeRes?.clone();
if (!clone?.clone().ok) Error('locale fetching error');
const clone = localeRes.clone();
if (!clone.clone().ok) Error('locale fetching error');

caches.open(this.cacheName).then(cache => cache.put(localeUrl, clone));
}

return new I18n(await localeRes.json());
return new I18n<Locale>(await localeRes.json());
}
}

Expand Down
10 changes: 2 additions & 8 deletions packages/sw/src/scripts/login-id.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
export function getUrlWithLoginId(url: string, loginId: string) {
export function getUrlWithLoginId(url: string, loginId: string): string {
const u = new URL(url, origin);
u.searchParams.append('loginId', loginId);
return u.toString();
}

export function getUrlWithoutLoginId(url: string) {
const u = new URL(url);
u.searchParams.delete('loginId');
u.searchParams.set('loginId', loginId);
return u.toString();
}
39 changes: 18 additions & 21 deletions packages/sw/src/scripts/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
* 各種操作
*/
import * as Misskey from 'misskey-js';
import { SwMessage, SwMessageOrderType } from '@/types';
import type { SwMessage, SwMessageOrderType } from '@/types';
import { getAccountFromId } from '@/scripts/get-account-from-id';
import { getUrlWithLoginId } from '@/scripts/login-id';

export const cli = new Misskey.api.APIClient({ origin, fetch: (...args) => fetch(...args) });
export const cli = new Misskey.api.APIClient({ origin, fetch: (...args): Promise<Response> => fetch(...args) });

export async function api<E extends keyof Misskey.Endpoints>(endpoint: E, userId: string, options?: Misskey.Endpoints[E]['req']) {
export async function api<E extends keyof Misskey.Endpoints>(endpoint: E, userId: string, options?: Misskey.Endpoints[E]['req']): Promise<void | ReturnType<typeof cli.request>> {
const account = await getAccountFromId(userId);
if (!account) return;

Expand All @@ -24,55 +24,52 @@ export function sendMarkAllAsRead(userId: string): Promise<null | undefined | vo
return new Promise(resolve => {
setTimeout(() => {
readBlockingStatus.set(userId, false);
api('notifications/mark-all-as-read', userId)
.then(resolve, resolve);
api('notifications/mark-all-as-read', userId).then(resolve, resolve);
}, 1000);
});
}

// rendered acctからユーザーを開く
export function openUser(acct: string, loginId?: string) {
export function openUser(acct: string, loginId?: string): ReturnType<typeof openClient> {
return openClient('push', `/@${acct}`, loginId, { acct });
}

// noteIdからノートを開く
export function openNote(noteId: string, loginId?: string) {
export function openNote(noteId: string, loginId?: string): ReturnType<typeof openClient> {
return openClient('push', `/notes/${noteId}`, loginId, { noteId });
}

// noteIdからノートを開く
export function openAntenna(antennaId: string, loginId: string) {
export function openAntenna(antennaId: string, loginId: string): ReturnType<typeof openClient> {
return openClient('push', `/timeline/antenna/${antennaId}`, loginId, { antennaId });
}

// post-formのオプションから投稿フォームを開く
export async function openPost(options: any, loginId?: string) {
export async function openPost(options: { initialText?: string; reply?: Misskey.entities.Note; renote?: Misskey.entities.Note }, loginId?: string): ReturnType<typeof openClient> {
// クエリを作成しておく
let url = '/share?';
if (options.initialText) url += `text=${options.initialText}&`;
if (options.reply) url += `replyId=${options.reply.id}&`;
if (options.renote) url += `renoteId=${options.renote.id}&`;
const url = '/share';
const query = new URLSearchParams();
if (options.initialText) query.set('text', options.initialText);
if (options.reply) query.set('replyId', options.reply.id);
if (options.renote) query.set('renoteId', options.renote.id);

return openClient('post', url, loginId, { options });
return openClient('post', `${url}?${query}`, loginId, { options });
}

export async function openClient(order: SwMessageOrderType, url: string, loginId?: string, query: any = {}) {
export async function openClient(order: SwMessageOrderType, url: string, loginId?: string, query: Record<string, SwMessage[string]> = {}): Promise<WindowClient | null> {
const client = await findClient();

if (client) {
client.postMessage({ type: 'order', ...query, order, loginId, url } as SwMessage);
client.postMessage({ type: 'order', ...query, order, loginId, url } satisfies SwMessage);
return client;
}

return globalThis.clients.openWindow(loginId ? getUrlWithLoginId(url, loginId) : url);
}

export async function findClient() {
export async function findClient(): Promise<WindowClient | null> {
const clients = await globalThis.clients.matchAll({
type: 'window',
});
for (const c of clients) {
if (!(new URL(c.url)).searchParams.has('zen')) return c;
}
return null;
return clients.find(c => !(new URL(c.url)).searchParams.has('zen')) ?? null;
}
12 changes: 4 additions & 8 deletions packages/sw/src/scripts/twemoji-base.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
export const twemojiSvgBase = '/twemoji';

export function char2fileName(char: string): string {
let codes = Array.from(char).map(x => x.codePointAt(0)?.toString(16));
let codes = Array.from(char)
.map(x => x.codePointAt(0)?.toString(16))
.filter(<T>(x: T | undefined): x is T => x !== undefined);
if (!codes.includes('200d')) codes = codes.filter(x => x !== 'fe0f');
codes = codes.filter(x => x && x.length);
codes = codes.filter(x => x.length !== 0);
return codes.join('-');
}

export function char2filePath(char: string): string {
return `${twemojiSvgBase}/${char2fileName(char)}.svg`;
}
18 changes: 0 additions & 18 deletions packages/sw/src/scripts/url.ts

This file was deleted.

Loading