diff --git a/src/client/app/common/scripts/gcd.ts b/src/client/app/common/scripts/gcd.ts deleted file mode 100644 index 9a19f9da6..000000000 --- a/src/client/app/common/scripts/gcd.ts +++ /dev/null @@ -1,2 +0,0 @@ -const gcd = (a, b) => !b ? a : gcd(b, a % b); -export default gcd; diff --git a/src/client/app/common/views/components/acct.vue b/src/client/app/common/views/components/acct.vue index 1ad222afd..2b5efe609 100644 --- a/src/client/app/common/views/components/acct.vue +++ b/src/client/app/common/views/components/acct.vue @@ -1,14 +1,20 @@ diff --git a/src/client/app/desktop/views/pages/deck/deck.column.vue b/src/client/app/desktop/views/pages/deck/deck.column.vue index 239b1b044..abb09775f 100644 --- a/src/client/app/desktop/views/pages/deck/deck.column.vue +++ b/src/client/app/desktop/views/pages/deck/deck.column.vue @@ -28,6 +28,7 @@ import Vue from 'vue'; import Menu from '../../../../common/views/components/menu.vue'; import contextmenu from '../../../api/contextmenu'; +import { countIf } from '../../../../../../prelude/array'; export default Vue.extend({ props: { @@ -117,7 +118,7 @@ export default Vue.extend({ toggleActive() { if (!this.isStacked) return; const vms = this.$store.state.settings.deck.layout.find(ids => ids.indexOf(this.column.id) != -1).map(id => this.getColumnVm(id)); - if (this.active && vms.filter(vm => vm.$el.classList.contains('active')).length == 1) return; + if (this.active && countIf(vm => vm.$el.classList.contains('active'), vms) == 1) return; this.active = !this.active; }, diff --git a/src/client/app/desktop/views/pages/user/user.header.vue b/src/client/app/desktop/views/pages/user/user.header.vue index d8f4656ed..4b434ec21 100644 --- a/src/client/app/desktop/views/pages/user/user.header.vue +++ b/src/client/app/desktop/views/pages/user/user.header.vue @@ -6,7 +6,7 @@

{{ user | userName }}

- + %fa:robot% %fa:map-marker% {{ user.profile.location }} %fa:birthday-cake% {{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳) diff --git a/src/client/app/mobile/views/components/drive.file-detail.vue b/src/client/app/mobile/views/components/drive.file-detail.vue index 43867211e..810889259 100644 --- a/src/client/app/mobile/views/components/drive.file-detail.vue +++ b/src/client/app/mobile/views/components/drive.file-detail.vue @@ -67,7 +67,7 @@ import Vue from 'vue'; import * as EXIF from 'exif-js'; import * as hljs from 'highlight.js'; -import gcd from '../../../common/scripts/gcd'; +import { gcd } from '../../../../../prelude/math'; export default Vue.extend({ props: ['file'], diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue index ddea43c9f..c1082f31a 100644 --- a/src/client/app/mobile/views/pages/user.vue +++ b/src/client/app/mobile/views/pages/user.vue @@ -16,7 +16,7 @@

{{ user | userName }}

- + %i18n:@follows-you%
diff --git a/src/games/reversi/core.ts b/src/games/reversi/core.ts index b610d4688..9199efa09 100644 --- a/src/games/reversi/core.ts +++ b/src/games/reversi/core.ts @@ -1,3 +1,5 @@ +import { count, countIf } from "../../prelude/array"; + // MISSKEY REVERSI ENGINE /** @@ -88,8 +90,8 @@ export default class Reversi { //#endregion // ゲームが始まった時点で片方の色の石しかないか、始まった時点で勝敗が決定するようなマップの場合がある - if (this.canPutSomewhere(BLACK).length == 0) { - if (this.canPutSomewhere(WHITE).length == 0) { + if (!this.canPutSomewhere(BLACK)) { + if (!this.canPutSomewhere(WHITE)) { this.turn = null; } else { this.turn = WHITE; @@ -101,14 +103,14 @@ export default class Reversi { * 黒石の数 */ public get blackCount() { - return this.board.filter(x => x === BLACK).length; + return count(BLACK, this.board); } /** * 白石の数 */ public get whiteCount() { - return this.board.filter(x => x === WHITE).length; + return count(BLACK, this.board); } /** @@ -170,9 +172,9 @@ export default class Reversi { private calcTurn() { // ターン計算 - if (this.canPutSomewhere(!this.prevColor).length > 0) { + if (this.canPutSomewhere(!this.prevColor)) { this.turn = !this.prevColor; - } else if (this.canPutSomewhere(this.prevColor).length > 0) { + } else if (this.canPutSomewhere(this.prevColor)) { this.turn = this.prevColor; } else { this.turn = null; @@ -204,10 +206,17 @@ export default class Reversi { /** * 打つことができる場所を取得します */ - public canPutSomewhere(color: Color): number[] { + public puttablePlaces(color: Color): number[] { return Array.from(this.board.keys()).filter(i => this.canPut(color, i)); } + /** + * 打つことができる場所があるかどうかを取得します + */ + public canPutSomewhere(color: Color): boolean { + return this.puttablePlaces(color).length > 0; + } + /** * 指定のマスに石を打つことができるかどうかを取得します * @param color 自分の色 diff --git a/src/mfm/html.ts b/src/mfm/html.ts index 2e38fe10a..b7fa5b6f0 100644 --- a/src/mfm/html.ts +++ b/src/mfm/html.ts @@ -4,10 +4,7 @@ const { JSDOM } = jsdom; import config from '../config'; import { INote } from '../models/note'; import { TextElement } from './parse'; - -function intersperse(sep: T, xs: T[]): T[] { - return [].concat(...xs.map(x => [sep, x])).slice(1); -} +import { intersperse } from '../prelude/array'; const handlers: { [key: string]: (window: any, token: any, mentionedRemoteUsers: INote['mentionedRemoteUsers']) => void } = { bold({ document }, { bold }) { diff --git a/src/prelude/README.md b/src/prelude/README.md new file mode 100644 index 000000000..bb728cfb1 --- /dev/null +++ b/src/prelude/README.md @@ -0,0 +1,3 @@ +# Prelude +このディレクトリのコードはJavaScriptの表現能力を補うためのコードです。 +Misskey固有の処理とは独立したコードの集まりですが、Misskeyのコードを読みやすくすることを目的としています。 diff --git a/src/prelude/array.ts b/src/prelude/array.ts new file mode 100644 index 000000000..aee17640e --- /dev/null +++ b/src/prelude/array.ts @@ -0,0 +1,11 @@ +export function countIf(f: (x: T) => boolean, xs: T[]): number { + return xs.filter(f).length; +} + +export function count(x: T, xs: T[]): number { + return countIf(y => x === y, xs); +} + +export function intersperse(sep: T, xs: T[]): T[] { + return [].concat(...xs.map(x => [sep, x])).slice(1); +} diff --git a/src/prelude/math.ts b/src/prelude/math.ts new file mode 100644 index 000000000..07b94bec3 --- /dev/null +++ b/src/prelude/math.ts @@ -0,0 +1,3 @@ +export function gcd(a: number, b: number): number { + return b === 0 ? a : gcd(b, a % b); +} diff --git a/src/server/activitypub/outbox.ts b/src/server/activitypub/outbox.ts index cc7e55b5d..a5e762eea 100644 --- a/src/server/activitypub/outbox.ts +++ b/src/server/activitypub/outbox.ts @@ -10,6 +10,7 @@ import { setResponseType } from '../activitypub'; import Note from '../../models/note'; import renderNote from '../../remote/activitypub/renderer/note'; +import { countIf } from '../../prelude/array'; export default async (ctx: Router.IRouterContext) => { const userId = new mongo.ObjectID(ctx.params.user); @@ -25,7 +26,7 @@ export default async (ctx: Router.IRouterContext) => { const page: boolean = ctx.request.query.page === 'true'; // Validate parameters - if (sinceIdErr || untilIdErr || pageErr || [sinceId, untilId].filter(x => x != null).length > 1) { + if (sinceIdErr || untilIdErr || pageErr || countIf(x => x != null, [sinceId, untilId]) > 1) { ctx.status = 400; return; } diff --git a/src/server/api/endpoints/notes/global-timeline.ts b/src/server/api/endpoints/notes/global-timeline.ts index e70fc5d76..5d93cd78e 100644 --- a/src/server/api/endpoints/notes/global-timeline.ts +++ b/src/server/api/endpoints/notes/global-timeline.ts @@ -4,6 +4,7 @@ import Mute from '../../../../models/mute'; import { pack } from '../../../../models/note'; import { ILocalUser } from '../../../../models/user'; import getParams from '../../get-params'; +import { countIf } from '../../../../prelude/array'; export const meta = { desc: { @@ -42,7 +43,7 @@ export default async (params: any, user: ILocalUser) => { if (psErr) throw psErr; // Check if only one of sinceId, untilId, sinceDate, untilDate specified - if ([ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate].filter(x => x != null).length > 1) { + if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) { throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified'; } diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts index 16cec8679..0eb7b6183 100644 --- a/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -5,6 +5,7 @@ import { getFriends } from '../../common/get-friends'; import { pack } from '../../../../models/note'; import { ILocalUser } from '../../../../models/user'; import getParams from '../../get-params'; +import { countIf } from '../../../../prelude/array'; export const meta = { desc: { @@ -86,7 +87,7 @@ export default async (params: any, user: ILocalUser) => { if (psErr) throw psErr; // Check if only one of sinceId, untilId, sinceDate, untilDate specified - if ([ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate].filter(x => x != null).length > 1) { + if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) { throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified'; } diff --git a/src/server/api/endpoints/notes/local-timeline.ts b/src/server/api/endpoints/notes/local-timeline.ts index ce84b4135..ff10e6fba 100644 --- a/src/server/api/endpoints/notes/local-timeline.ts +++ b/src/server/api/endpoints/notes/local-timeline.ts @@ -4,6 +4,7 @@ import Mute from '../../../../models/mute'; import { pack } from '../../../../models/note'; import { ILocalUser } from '../../../../models/user'; import getParams from '../../get-params'; +import { countIf } from '../../../../prelude/array'; export const meta = { desc: { @@ -48,7 +49,7 @@ export default async (params: any, user: ILocalUser) => { if (psErr) throw psErr; // Check if only one of sinceId, untilId, sinceDate, untilDate specified - if ([ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate].filter(x => x != null).length > 1) { + if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) { throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified'; } diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts index 089e7a182..5f3844987 100644 --- a/src/server/api/endpoints/notes/timeline.ts +++ b/src/server/api/endpoints/notes/timeline.ts @@ -5,6 +5,7 @@ import { getFriends } from '../../common/get-friends'; import { pack } from '../../../../models/note'; import { ILocalUser } from '../../../../models/user'; import getParams from '../../get-params'; +import { countIf } from '../../../../prelude/array'; export const meta = { desc: { @@ -86,7 +87,7 @@ export default async (params: any, user: ILocalUser) => { if (psErr) throw psErr; // Check if only one of sinceId, untilId, sinceDate, untilDate specified - if ([ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate].filter(x => x != null).length > 1) { + if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) { throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified'; } diff --git a/src/server/api/endpoints/users/notes.ts b/src/server/api/endpoints/users/notes.ts index 42c31189d..1ab7786a1 100644 --- a/src/server/api/endpoints/users/notes.ts +++ b/src/server/api/endpoints/users/notes.ts @@ -3,6 +3,7 @@ import getHostLower from '../../common/get-host-lower'; import Note, { pack } from '../../../../models/note'; import User, { ILocalUser } from '../../../../models/user'; import getParams from '../../get-params'; +import { countIf } from '../../../../prelude/array'; export const meta = { desc: { @@ -110,7 +111,7 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => } // Check if only one of sinceId, untilId, sinceDate, untilDate specified - if ([ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate].filter(x => x != null).length > 1) { + if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) { throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified'; }