diff --git a/src/client/app/common/scripts/streaming/stream-manager.ts b/src/client/app/common/scripts/streaming/stream-manager.ts index 568b8b0372..8dd06f67d3 100644 --- a/src/client/app/common/scripts/streaming/stream-manager.ts +++ b/src/client/app/common/scripts/streaming/stream-manager.ts @@ -1,6 +1,7 @@ import { EventEmitter } from 'eventemitter3'; import * as uuid from 'uuid'; import Connection from './stream'; +import { erase } from '../../../../../prelude/array'; /** * ストリーム接続を管理するクラス @@ -89,7 +90,7 @@ export default abstract class StreamManager<T extends Connection> extends EventE * @param userId use で発行したユーザーID */ public dispose(userId) { - this.users = this.users.filter(id => id != userId); + this.users = erase(userId, this.users); this._connection.user = `Managed (${ this.users.length })`; diff --git a/src/client/app/common/views/components/poll-editor.vue b/src/client/app/common/views/components/poll-editor.vue index 115c934c8b..30d9799fec 100644 --- a/src/client/app/common/views/components/poll-editor.vue +++ b/src/client/app/common/views/components/poll-editor.vue @@ -20,6 +20,7 @@ <script lang="ts"> import Vue from 'vue'; +import { erase } from '../../../../../prelude/array'; export default Vue.extend({ data() { return { @@ -53,7 +54,7 @@ export default Vue.extend({ get() { return { - choices: this.choices.filter(choice => choice != '') + choices: erase('', this.choices) } }, diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue index f6f52c8f1f..65dc9eb9c2 100644 --- a/src/client/app/desktop/views/components/post-form.vue +++ b/src/client/app/desktop/views/components/post-form.vue @@ -62,6 +62,7 @@ import getFace from '../../../common/scripts/get-face'; import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue'; import parse from '../../../../../mfm/parse'; import { host } from '../../../config'; +import { erase } from '../../../../../prelude/array'; export default Vue.extend({ components: { @@ -346,7 +347,7 @@ export default Vue.extend({ }, removeVisibleUser(user) { - this.visibleUsers = this.visibleUsers.filter(u => u != user); + this.visibleUsers = erase(user, this.visibleUsers); }, post() { diff --git a/src/client/app/mios.ts b/src/client/app/mios.ts index c2ec7f1750..0f72cd2f34 100644 --- a/src/client/app/mios.ts +++ b/src/client/app/mios.ts @@ -17,6 +17,7 @@ import Err from './common/views/components/connect-failed.vue'; import { LocalTimelineStreamManager } from './common/scripts/streaming/local-timeline'; import { HybridTimelineStreamManager } from './common/scripts/streaming/hybrid-timeline'; import { GlobalTimelineStreamManager } from './common/scripts/streaming/global-timeline'; +import { erase } from '../../prelude/array'; //#region api requests let spinner = null; @@ -537,7 +538,7 @@ export default class MiOS extends EventEmitter { } public unregisterStreamConnection(connection: Connection) { - this.connections = this.connections.filter(c => c != connection); + this.connections = erase(connection, this.connections); } } diff --git a/src/client/app/mobile/views/components/post-form.vue b/src/client/app/mobile/views/components/post-form.vue index 644e27cce8..8107c1f3a7 100644 --- a/src/client/app/mobile/views/components/post-form.vue +++ b/src/client/app/mobile/views/components/post-form.vue @@ -59,6 +59,7 @@ import MkVisibilityChooser from '../../../common/views/components/visibility-cho import getFace from '../../../common/scripts/get-face'; import parse from '../../../../../mfm/parse'; import { host } from '../../../config'; +import { erase } from '../../../../../prelude/array'; export default Vue.extend({ components: { @@ -262,7 +263,7 @@ export default Vue.extend({ }, removeVisibleUser(user) { - this.visibleUsers = this.visibleUsers.filter(u => u != user); + this.visibleUsers = erase(user, this.visibleUsers); }, clear() { diff --git a/src/client/app/store.ts b/src/client/app/store.ts index 53f3eefc08..08dd9f9920 100644 --- a/src/client/app/store.ts +++ b/src/client/app/store.ts @@ -4,6 +4,7 @@ import * as nestedProperty from 'nested-property'; import MiOS from './mios'; import { hostname } from './config'; +import { erase } from '../../prelude/array'; const defaultSettings = { home: null, @@ -195,7 +196,7 @@ export default (os: MiOS) => new Vuex.Store({ removeDeckColumn(state, id) { state.deck.columns = state.deck.columns.filter(c => c.id != id); - state.deck.layout = state.deck.layout.map(ids => ids.filter(x => x != id)); + state.deck.layout = state.deck.layout.map(ids => erase(id, ids)); state.deck.layout = state.deck.layout.filter(ids => ids.length > 0); }, @@ -266,7 +267,7 @@ export default (os: MiOS) => new Vuex.Store({ stackLeftDeckColumn(state, id) { const i = state.deck.layout.findIndex(ids => ids.indexOf(id) != -1); - state.deck.layout = state.deck.layout.map(ids => ids.filter(x => x != id)); + state.deck.layout = state.deck.layout.map(ids => erase(id, ids)); const left = state.deck.layout[i - 1]; if (left) state.deck.layout[i - 1].push(id); state.deck.layout = state.deck.layout.filter(ids => ids.length > 0); @@ -274,7 +275,7 @@ export default (os: MiOS) => new Vuex.Store({ popRightDeckColumn(state, id) { const i = state.deck.layout.findIndex(ids => ids.indexOf(id) != -1); - state.deck.layout = state.deck.layout.map(ids => ids.filter(x => x != id)); + state.deck.layout = state.deck.layout.map(ids => erase(id, ids)); state.deck.layout.splice(i + 1, 0, [id]); state.deck.layout = state.deck.layout.filter(ids => ids.length > 0); }, diff --git a/src/client/app/sw.js b/src/client/app/sw.js index ac7ea20acf..d381bfb7a5 100644 --- a/src/client/app/sw.js +++ b/src/client/app/sw.js @@ -3,6 +3,7 @@ */ import composeNotification from './common/scripts/compose-notification'; +import { erase } from '../../prelude/array'; // キャッシュするリソース const cachee = [ @@ -24,8 +25,7 @@ self.addEventListener('activate', ev => { // Clean up old caches ev.waitUntil( caches.keys().then(keys => Promise.all( - keys - .filter(key => key != _VERSION_) + erase(_VERSION_, keys) .map(key => caches.delete(key)) )) ); diff --git a/src/prelude/array.ts b/src/prelude/array.ts index 9a3c266d6d..a2a6bbd4c6 100644 --- a/src/prelude/array.ts +++ b/src/prelude/array.ts @@ -13,3 +13,7 @@ export function concat<T>(xss: T[][]): T[] { export function intersperse<T>(sep: T, xs: T[]): T[] { return concat(xs.map(x => [sep, x])).slice(1); } + +export function erase<T>(x: T, xs: T[]): T[] { + return xs.filter(y => x !== y); +} diff --git a/src/server/api/endpoints/hashtags/trend.ts b/src/server/api/endpoints/hashtags/trend.ts index 01dfccc71c..e7c08ca9f0 100644 --- a/src/server/api/endpoints/hashtags/trend.ts +++ b/src/server/api/endpoints/hashtags/trend.ts @@ -1,4 +1,5 @@ import Note from '../../../../models/note'; +import { erase } from '../../../../prelude/array'; /* トレンドに載るためには「『直近a分間のユニーク投稿数が今からa分前~今からb分前の間のユニーク投稿数のn倍以上』のハッシュタグの上位5位以内に入る」ことが必要 @@ -85,8 +86,7 @@ export default () => new Promise(async (res, rej) => { //#endregion // タグを人気順に並べ替え - let hots = (await Promise.all(hotsPromises)) - .filter(x => x != null) + let hots = erase(null, await Promise.all(hotsPromises)) .sort((a, b) => b.count - a.count) .map(tag => tag.name) .slice(0, max); diff --git a/src/server/api/endpoints/notes/search_by_tag.ts b/src/server/api/endpoints/notes/search_by_tag.ts index 82f11a9775..77082c2600 100644 --- a/src/server/api/endpoints/notes/search_by_tag.ts +++ b/src/server/api/endpoints/notes/search_by_tag.ts @@ -5,6 +5,7 @@ import Mute from '../../../../models/mute'; import { getFriendIds } from '../../common/get-friends'; import { pack } from '../../../../models/note'; import getParams from '../../get-params'; +import { erase } from '../../../../prelude/array'; export const meta = { desc: { @@ -103,23 +104,23 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => if (psErr) throw psErr; if (ps.includeUserUsernames != null) { - const ids = (await Promise.all(ps.includeUserUsernames.map(async (username) => { + const ids = erase(null, await Promise.all(ps.includeUserUsernames.map(async (username) => { const _user = await User.findOne({ usernameLower: username.toLowerCase() }); return _user ? _user._id : null; - }))).filter(id => id != null); + }))); ids.forEach(id => ps.includeUserIds.push(id)); } if (ps.excludeUserUsernames != null) { - const ids = (await Promise.all(ps.excludeUserUsernames.map(async (username) => { + const ids = erase(null, await Promise.all(ps.excludeUserUsernames.map(async (username) => { const _user = await User.findOne({ usernameLower: username.toLowerCase() }); return _user ? _user._id : null; - }))).filter(id => id != null); + }))); ids.forEach(id => ps.excludeUserIds.push(id)); } diff --git a/src/services/note/create.ts b/src/services/note/create.ts index 11e3755863..4759497c63 100644 --- a/src/services/note/create.ts +++ b/src/services/note/create.ts @@ -24,6 +24,7 @@ import isQuote from '../../misc/is-quote'; import { TextElementMention } from '../../mfm/parse/elements/mention'; import { TextElementHashtag } from '../../mfm/parse/elements/hashtag'; import { updateNoteStats } from '../update-chart'; +import { erase } from '../../prelude/array'; type NotificationType = 'reply' | 'renote' | 'quote' | 'mention'; @@ -103,7 +104,7 @@ export default async (user: IUser, data: Option, silent = false) => new Promise< if (data.viaMobile == null) data.viaMobile = false; if (data.visibleUsers) { - data.visibleUsers = data.visibleUsers.filter(x => x != null); + data.visibleUsers = erase(null, data.visibleUsers); } if (data.reply && data.reply.deletedAt != null) { @@ -547,13 +548,13 @@ async function extractMentionedUsers(tokens: ReturnType<typeof parse>): Promise< )]; const mentionedUsers = [...new Set( - (await Promise.all(mentionTokens.map(async m => { + erase(null, await Promise.all(mentionTokens.map(async m => { try { return await resolveUser(m.username, m.host); } catch (e) { return null; } - }))).filter(x => x != null) + }))) )]; return mentionedUsers;