diff options
| author | かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> | 2024-09-10 18:39:53 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-09-10 18:39:53 +0900 |
| commit | 837a8e15d893a670ab2ce51b3ec87e6b62a51da7 (patch) | |
| tree | 0b651782db2bf440f1c789606d6367226f2e2253 /packages/frontend-shared | |
| parent | Dev: cypressをdev containerで実行可に(e2e-dev-container) (#14526) (diff) | |
| download | sharkey-837a8e15d893a670ab2ce51b3ec87e6b62a51da7.tar.gz sharkey-837a8e15d893a670ab2ce51b3ec87e6b62a51da7.tar.bz2 sharkey-837a8e15d893a670ab2ce51b3ec87e6b62a51da7.zip | |
refactor(frontend): frontend-embed/src/to-be-sharedを共通化 (#14536)
* refactor(frontend): shouldCollapsedを共通化
* refactor(frontend): config.js, worker-multi-dispatch.js, intl-const.jsを共通化
* fix(frontend-shared): fix type error
* refactor(frontend): is-link.jsと、同一の振る舞いをする記述を共通化
* fix
* fix lint
* lint fixes
Diffstat (limited to 'packages/frontend-shared')
| -rw-r--r-- | packages/frontend-shared/@types/global.d.ts | 25 | ||||
| -rw-r--r-- | packages/frontend-shared/eslint.config.js | 6 | ||||
| -rw-r--r-- | packages/frontend-shared/js/collapsed.ts | 22 | ||||
| -rw-r--r-- | packages/frontend-shared/js/config.ts | 28 | ||||
| -rw-r--r-- | packages/frontend-shared/js/emoji-base.ts | 4 | ||||
| -rw-r--r-- | packages/frontend-shared/js/intl-const.ts | 51 | ||||
| -rw-r--r-- | packages/frontend-shared/js/is-link.ts | 12 | ||||
| -rw-r--r-- | packages/frontend-shared/js/worker-multi-dispatch.ts | 86 | ||||
| -rw-r--r-- | packages/frontend-shared/tsconfig.json | 7 |
9 files changed, 238 insertions, 3 deletions
diff --git a/packages/frontend-shared/@types/global.d.ts b/packages/frontend-shared/@types/global.d.ts new file mode 100644 index 0000000000..4b8d679e75 --- /dev/null +++ b/packages/frontend-shared/@types/global.d.ts @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type FIXME = any; + +declare const _LANGS_: string[][]; +declare const _VERSION_: string; +declare const _ENV_: string; +declare const _DEV_: boolean; +declare const _PERF_PREFIX_: string; +declare const _DATA_TRANSFER_DRIVE_FILE_: string; +declare const _DATA_TRANSFER_DRIVE_FOLDER_: string; +declare const _DATA_TRANSFER_DECK_COLUMN_: string; + +// for dev-mode +declare const _LANGS_FULL_: string[][]; + +// TagCanvas +interface Window { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TagCanvas: any; +} diff --git a/packages/frontend-shared/eslint.config.js b/packages/frontend-shared/eslint.config.js index a15fb29e37..cd4641a270 100644 --- a/packages/frontend-shared/eslint.config.js +++ b/packages/frontend-shared/eslint.config.js @@ -14,7 +14,11 @@ export default [ }, ...pluginVue.configs['flat/recommended'], { - files: ['js/**/*.{ts,vue}', '**/*.vue'], + files: [ + '@types/**/*.ts', + 'js/**/*.ts', + '**/*.vue', + ], languageOptions: { globals: { ...Object.fromEntries(Object.entries(globals.node).map(([key]) => [key, 'off'])), diff --git a/packages/frontend-shared/js/collapsed.ts b/packages/frontend-shared/js/collapsed.ts new file mode 100644 index 0000000000..af1f88cb73 --- /dev/null +++ b/packages/frontend-shared/js/collapsed.ts @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import * as Misskey from 'misskey-js'; + +export function shouldCollapsed(note: Misskey.entities.Note, urls: string[]): boolean { + const collapsed = note.cw == null && ( + (note.text != null && ( + (note.text.includes('$[x2')) || + (note.text.includes('$[x3')) || + (note.text.includes('$[x4')) || + (note.text.includes('$[scale')) || + (note.text.split('\n').length > 9) || + (note.text.length > 500) || + (urls.length >= 4) + )) || (note.files != null && note.files.length >= 5) + ); + + return collapsed; +} diff --git a/packages/frontend-shared/js/config.ts b/packages/frontend-shared/js/config.ts new file mode 100644 index 0000000000..ae1dcae10b --- /dev/null +++ b/packages/frontend-shared/js/config.ts @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import type { Locale } from '../../../locales/index.js'; + +// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing +const address = new URL(document.querySelector<HTMLMetaElement>('meta[property="instance_url"]')?.content || location.href); +const siteName = document.querySelector<HTMLMetaElement>('meta[property="og:site_name"]')?.content; + +export const host = address.host; +export const hostname = address.hostname; +export const url = address.origin; +export const apiUrl = location.origin + '/api'; +export const wsOrigin = location.origin; +export const lang = localStorage.getItem('lang') ?? 'en-US'; +export const langs = _LANGS_; +const preParseLocale = localStorage.getItem('locale'); +export let locale: Locale = preParseLocale ? JSON.parse(preParseLocale) : null; +export const version = _VERSION_; +export const instanceName = (siteName === 'Misskey' || siteName == null) ? host : siteName; +export const ui = localStorage.getItem('ui'); +export const debug = localStorage.getItem('debug') === 'true'; + +export function updateLocale(newLocale: Locale): void { + locale = newLocale; +} diff --git a/packages/frontend-shared/js/emoji-base.ts b/packages/frontend-shared/js/emoji-base.ts index a01540a3e4..5fbbc4ea84 100644 --- a/packages/frontend-shared/js/emoji-base.ts +++ b/packages/frontend-shared/js/emoji-base.ts @@ -19,7 +19,7 @@ export function char2fluentEmojiFilePath(char: string): string { // Fluent Emojiは国旗非対応 https://github.com/microsoft/fluentui-emoji/issues/25 if (codes[0]?.startsWith('1f1')) return char2twemojiFilePath(char); if (!codes.includes('200d')) codes = codes.filter(x => x !== 'fe0f'); - codes = codes.filter(x => x && x.length); - const fileName = codes.map(x => x!.padStart(4, '0')).join('-'); + codes = codes.filter(x => x != null && x.length > 0); + const fileName = (codes as string[]).map(x => x.padStart(4, '0')).join('-'); return `${fluentEmojiPngBase}/${fileName}.png`; } diff --git a/packages/frontend-shared/js/intl-const.ts b/packages/frontend-shared/js/intl-const.ts new file mode 100644 index 0000000000..33b65b6e9b --- /dev/null +++ b/packages/frontend-shared/js/intl-const.ts @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { lang } from '@@/js/config.js'; + +// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition +export const versatileLang = (lang ?? 'ja-JP').replace('ja-KS', 'ja-JP'); + +let _dateTimeFormat: Intl.DateTimeFormat; +try { + _dateTimeFormat = new Intl.DateTimeFormat(versatileLang, { + year: 'numeric', + month: 'numeric', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + }); +} catch (err) { + console.warn(err); + if (_DEV_) console.log('[Intl] Fallback to en-US'); + + // Fallback to en-US + _dateTimeFormat = new Intl.DateTimeFormat('en-US', { + year: 'numeric', + month: 'numeric', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + }); +} +export const dateTimeFormat = _dateTimeFormat; + +export const timeZone = dateTimeFormat.resolvedOptions().timeZone; + +export const hemisphere = /^(australia|pacific|antarctica|indian)\//i.test(timeZone) ? 'S' : 'N'; + +let _numberFormat: Intl.NumberFormat; +try { + _numberFormat = new Intl.NumberFormat(versatileLang); +} catch (err) { + console.warn(err); + if (_DEV_) console.log('[Intl] Fallback to en-US'); + + // Fallback to en-US + _numberFormat = new Intl.NumberFormat('en-US'); +} +export const numberFormat = _numberFormat; diff --git a/packages/frontend-shared/js/is-link.ts b/packages/frontend-shared/js/is-link.ts new file mode 100644 index 0000000000..946f86400e --- /dev/null +++ b/packages/frontend-shared/js/is-link.ts @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export function isLink(el: HTMLElement) { + if (el.tagName === 'A') return true; + if (el.parentElement) { + return isLink(el.parentElement); + } + return false; +} diff --git a/packages/frontend-shared/js/worker-multi-dispatch.ts b/packages/frontend-shared/js/worker-multi-dispatch.ts new file mode 100644 index 0000000000..5d393ed1ed --- /dev/null +++ b/packages/frontend-shared/js/worker-multi-dispatch.ts @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +function defaultUseWorkerNumber(prev: number) { + return prev + 1; +} + +type WorkerNumberGetter = (prev: number, totalWorkers: number) => number; + +export class WorkerMultiDispatch<POST = unknown, RETURN = unknown> { + private symbol = Symbol('WorkerMultiDispatch'); + private workers: Worker[] = []; + private terminated = false; + private prevWorkerNumber = 0; + private getUseWorkerNumber: WorkerNumberGetter; + private finalizationRegistry: FinalizationRegistry<symbol>; + + constructor(workerConstructor: () => Worker, concurrency: number, getUseWorkerNumber = defaultUseWorkerNumber) { + this.getUseWorkerNumber = getUseWorkerNumber; + for (let i = 0; i < concurrency; i++) { + this.workers.push(workerConstructor()); + } + + this.finalizationRegistry = new FinalizationRegistry(() => { + this.terminate(); + }); + this.finalizationRegistry.register(this, this.symbol); + + if (_DEV_) console.log('WorkerMultiDispatch: Created', this); + } + + public postMessage(message: POST, options?: Transferable[] | StructuredSerializeOptions, useWorkerNumber: WorkerNumberGetter = this.getUseWorkerNumber) { + let workerNumber = useWorkerNumber(this.prevWorkerNumber, this.workers.length); + workerNumber = Math.abs(Math.round(workerNumber)) % this.workers.length; + if (_DEV_) console.log('WorkerMultiDispatch: Posting message to worker', workerNumber, useWorkerNumber); + this.prevWorkerNumber = workerNumber; + + // 不毛だがunionをoverloadに突っ込めない + // https://stackoverflow.com/questions/66507585/overload-signatures-union-types-and-no-overload-matches-this-call-error + // https://github.com/microsoft/TypeScript/issues/14107 + if (Array.isArray(options)) { + this.workers[workerNumber].postMessage(message, options); + } else { + this.workers[workerNumber].postMessage(message, options); + } + return workerNumber; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public addListener(callback: (this: Worker, ev: MessageEvent<RETURN>) => any, options?: boolean | AddEventListenerOptions) { + this.workers.forEach(worker => { + worker.addEventListener('message', callback, options); + }); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public removeListener(callback: (this: Worker, ev: MessageEvent<RETURN>) => any, options?: boolean | AddEventListenerOptions) { + this.workers.forEach(worker => { + worker.removeEventListener('message', callback, options); + }); + } + + public terminate() { + this.terminated = true; + if (_DEV_) console.log('WorkerMultiDispatch: Terminating', this); + this.workers.forEach(worker => { + worker.terminate(); + }); + this.workers = []; + this.finalizationRegistry.unregister(this); + } + + public isTerminated() { + return this.terminated; + } + + public getWorkers() { + return this.workers; + } + + public getSymbol() { + return this.symbol; + } +} diff --git a/packages/frontend-shared/tsconfig.json b/packages/frontend-shared/tsconfig.json index fa0b765534..09a8ff76aa 100644 --- a/packages/frontend-shared/tsconfig.json +++ b/packages/frontend-shared/tsconfig.json @@ -16,7 +16,13 @@ "experimentalDecorators": true, "noImplicitReturns": true, "esModuleInterop": true, + "baseUrl": ".", + "paths": { + "@/*": ["./*"], + "@@/*": ["./*"] + }, "typeRoots": [ + "./@types", "./node_modules/@types" ], "lib": [ @@ -25,6 +31,7 @@ ] }, "include": [ + "@types/**/*.ts", "js/**/*" ], "exclude": [ |