From a34cc47a11d5fffa4e4e4817d9d8f4d741cc3ead Mon Sep 17 00:00:00 2001 From: rinsuki <428rinsuki+git@gmail.com> Date: Sun, 17 Jun 2018 17:43:54 +0900 Subject: [PATCH 1/7] tsconfig.json noImplicitAny: true --- tsconfig.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index c407d554ee..125a0c0943 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "allowJs": true, "noEmitOnError": false, - "noImplicitAny": false, + "noImplicitAny": true, "noImplicitReturns": true, "noUnusedParameters": false, "noUnusedLocals": true, @@ -14,7 +14,7 @@ "removeComments": false, "noLib": false, "strict": true, - "strictNullChecks": false + "strictNullChecks": false }, "compileOnSave": false, "include": [ From 71da205ab781bca3ef0d2a6ddfdcdb2a2eca2817 Mon Sep 17 00:00:00 2001 From: rinsuki <428rinsuki+git@gmail.com> Date: Sun, 17 Jun 2018 17:45:59 +0900 Subject: [PATCH 2/7] fix --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 125a0c0943..76221c282a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,7 @@ "removeComments": false, "noLib": false, "strict": true, - "strictNullChecks": false + "strictNullChecks": false }, "compileOnSave": false, "include": [ From f19075c50a4247d234b9e28ba48d35ac8d6316d2 Mon Sep 17 00:00:00 2001 From: rinsuki <428rinsuki+git@gmail.com> Date: Sun, 17 Jun 2018 17:57:50 +0900 Subject: [PATCH 3/7] upgrade font-awesome packages --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 9cbbab1984..bf49a6599f 100644 --- a/package.json +++ b/package.json @@ -23,10 +23,10 @@ "format": "gulp format" }, "dependencies": { - "@fortawesome/fontawesome": "1.0.1", - "@fortawesome/fontawesome-free-brands": "5.0.2", - "@fortawesome/fontawesome-free-regular": "5.0.2", - "@fortawesome/fontawesome-free-solid": "5.0.2", + "@fortawesome/fontawesome": "1.1.8", + "@fortawesome/fontawesome-free-brands": "5.0.13", + "@fortawesome/fontawesome-free-regular": "5.0.13", + "@fortawesome/fontawesome-free-solid": "5.0.13", "@koa/cors": "2.2.1", "@prezzemolo/rap": "0.1.2", "@prezzemolo/zip": "0.0.3", From 871f8867023804e8685f405c95cebae76b955e24 Mon Sep 17 00:00:00 2001 From: rinsuki <428rinsuki+git@gmail.com> Date: Sun, 17 Jun 2018 19:09:24 +0900 Subject: [PATCH 4/7] build:ts success --- gulpfile.ts | 4 ++-- locales/index.ts | 14 ++++++++++--- src/build/fa.ts | 16 +++++++-------- src/build/i18n.ts | 21 ++++++++++--------- src/client/docs/api/gulpfile.ts | 19 ++++++++++------- src/client/docs/gulpfile.ts | 4 ++-- src/client/docs/vars.ts | 2 +- yarn.lock | 36 ++++++++++++++++++++++----------- 8 files changed, 72 insertions(+), 44 deletions(-) diff --git a/gulpfile.ts b/gulpfile.ts index fa1155878c..49a80879d2 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -8,12 +8,12 @@ import * as gutil from 'gulp-util'; import * as ts from 'gulp-typescript'; const sourcemaps = require('gulp-sourcemaps'); import tslint from 'gulp-tslint'; -import cssnano = require('gulp-cssnano'); +const cssnano = require('gulp-cssnano'); import * as uglifyComposer from 'gulp-uglify/composer'; import pug = require('gulp-pug'); import * as rimraf from 'rimraf'; import chalk from 'chalk'; -import imagemin = require('gulp-imagemin'); +const imagemin = require('gulp-imagemin'); import * as rename from 'gulp-rename'; import * as mocha from 'gulp-mocha'; import * as replace from 'gulp-replace'; diff --git a/locales/index.ts b/locales/index.ts index 319d178e0a..3b4f76b06a 100644 --- a/locales/index.ts +++ b/locales/index.ts @@ -5,12 +5,16 @@ import * as fs from 'fs'; import * as yaml from 'js-yaml'; -const loadLang = lang => yaml.safeLoad( - fs.readFileSync(`./locales/${lang}.yml`, 'utf-8')); +export type LangKey = 'de' | 'en' | 'fr' | 'ja' | 'pl'; +export type LocaleObjectChildren = LocaleObject | string | undefined; +export type LocaleObject = {[key: string]: LocaleObjectChildren }; + +const loadLang = (lang: LangKey) => yaml.safeLoad( + fs.readFileSync(`./locales/${lang}.yml`, 'utf-8')) as LocaleObject; const native = loadLang('ja'); -const langs = { +const langs: {[key in LangKey]: LocaleObject} = { 'de': loadLang('de'), 'en': loadLang('en'), 'fr': loadLang('fr'), @@ -23,4 +27,8 @@ Object.entries(langs).map(([, locale]) => { locale = Object.assign({}, native, locale); }); +export function isAvailableLanguage(lang: string): lang is LangKey { + return lang in langs; +} + export default langs; diff --git a/src/build/fa.ts b/src/build/fa.ts index 111c19ae66..077bb51e6d 100644 --- a/src/build/fa.ts +++ b/src/build/fa.ts @@ -3,18 +3,18 @@ */ import * as fontawesome from '@fortawesome/fontawesome'; -import * as regular from '@fortawesome/fontawesome-free-regular'; -import * as solid from '@fortawesome/fontawesome-free-solid'; -import * as brands from '@fortawesome/fontawesome-free-brands'; +import regular from '@fortawesome/fontawesome-free-regular'; +import solid from '@fortawesome/fontawesome-free-solid'; +import brands from '@fortawesome/fontawesome-free-brands'; fontawesome.library.add(regular, solid, brands); export const pattern = /%fa:(.+?)%/g; -export const replacement = (match, key) => { +export const replacement = (match: string, key: string) => { const args = key.split(' '); let prefix = 'fas'; - const classes = []; + const classes: string[] = []; let transform = ''; let name; @@ -34,12 +34,12 @@ export const replacement = (match, key) => { } }); - const icon = fontawesome.icon({ prefix, iconName: name }, { - classes: classes + const icon = fontawesome.icon({ prefix, iconName: name } as fontawesome.IconLookup, { + classes: classes, + transform: fontawesome.parse.transform(transform) }); if (icon) { - icon.transform = fontawesome.parse.transform(transform); return `${icon.html[0]}`; } else { console.warn(`'${name}' not found in fa`); diff --git a/src/build/i18n.ts b/src/build/i18n.ts index 35854055d0..308ff0da00 100644 --- a/src/build/i18n.ts +++ b/src/build/i18n.ts @@ -2,7 +2,7 @@ * Replace i18n texts */ -import locale from '../../locales'; +import locale, { isAvailableLanguage, LocaleObject, LocaleObjectChildren } from '../../locales'; export default class Replacer { private lang: string; @@ -16,19 +16,19 @@ export default class Replacer { this.replacement = this.replacement.bind(this); } - private get(path: string, key: string) { - const texts = locale[this.lang]; - - if (texts == null) { + private get(path: string, key: string): string { + if (!isAvailableLanguage(this.lang)) { console.warn(`lang '${this.lang}' is not supported`); return key; // Fallback } - let text = texts; + const texts = locale[this.lang]; + + let text: LocaleObjectChildren = texts; if (path) { if (text.hasOwnProperty(path)) { - text = text[path]; + text = text[path] as LocaleObject; } else { console.warn(`path '${path}' not found in '${this.lang}'`); return key; // Fallback @@ -38,7 +38,7 @@ export default class Replacer { // Check the key existance const error = key.split('.').some(k => { if (text.hasOwnProperty(k)) { - text = text[k]; + text = (text as LocaleObject)[k]; return false; } else { return true; @@ -48,12 +48,15 @@ export default class Replacer { if (error) { console.warn(`key '${key}' not found in '${path}' of '${this.lang}'`); return key; // Fallback + } else if (typeof text !== "string") { + console.warn(`key '${key}' is not string in '${path}' of '${this.lang}'`); + return key; // Fallback } else { return text; } } - public replacement(match, key) { + public replacement(match: string, key: string) { let path = null; if (key.indexOf('|') != -1) { diff --git a/src/client/docs/api/gulpfile.ts b/src/client/docs/api/gulpfile.ts index 9980ede231..0eb8b88287 100644 --- a/src/client/docs/api/gulpfile.ts +++ b/src/client/docs/api/gulpfile.ts @@ -19,9 +19,10 @@ import generateVars from '../vars'; const langs = Object.keys(locales); -const kebab = string => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase(); +const kebab = (string: string) => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase(); -const parseParam = param => { +// WIP type +const parseParam = (param: any) => { const id = param.type.match(/^id\((.+?)\)|^id/); const entity = param.type.match(/^entity\((.+?)\)/); const isObject = /^object/.test(param.type); @@ -57,7 +58,7 @@ const parseParam = param => { return param; }; -const sortParams = params => { +const sortParams = (params: Array<{name: string}>) => { params.sort((a, b) => { if (a.name < b.name) return -1; @@ -68,14 +69,15 @@ const sortParams = params => { return params; }; -const extractDefs = params => { - let defs = []; +// WIP type +const extractDefs = (params: any[]) => { + let defs: any[] = []; params.forEach(param => { if (param.def) { defs.push({ name: param.defName, - params: sortParams(param.def.map(p => parseParam(p))) + params: sortParams(param.def.map((p: any) => parseParam(p))) }); const childDefs = extractDefs(param.def); @@ -109,8 +111,10 @@ gulp.task('doc:api:endpoints', async () => { path: ep.endpoint }, desc: ep.desc, + // @ts-ignore params: sortParams(ep.params.map(p => parseParam(p))), paramDefs: extractDefs(ep.params), + // @ts-ignore res: ep.res ? sortParams(ep.res.map(p => parseParam(p))) : null, resDefs: ep.res ? extractDefs(ep.res) : null, }; @@ -155,7 +159,8 @@ gulp.task('doc:api:entities', async () => { const vars = { name: entity.name, desc: entity.desc, - props: sortParams(entity.props.map(p => parseParam(p))), + // WIP type + props: sortParams(entity.props.map((p: any) => parseParam(p))), propDefs: extractDefs(entity.props), }; langs.forEach(lang => { diff --git a/src/client/docs/gulpfile.ts b/src/client/docs/gulpfile.ts index 56bf6188c8..4683a04659 100644 --- a/src/client/docs/gulpfile.ts +++ b/src/client/docs/gulpfile.ts @@ -8,8 +8,8 @@ import * as glob from 'glob'; import * as gulp from 'gulp'; import * as pug from 'pug'; import * as mkdirp from 'mkdirp'; -import stylus = require('gulp-stylus'); -import cssnano = require('gulp-cssnano'); +const stylus = require('gulp-stylus'); +const cssnano = require('gulp-cssnano'); import I18nReplacer from '../../build/i18n'; import fa from '../../build/fa'; diff --git a/src/client/docs/vars.ts b/src/client/docs/vars.ts index 32b961aaa9..93082767e3 100644 --- a/src/client/docs/vars.ts +++ b/src/client/docs/vars.ts @@ -38,7 +38,7 @@ export default async function(): Promise<{ [key: string]: any }> { vars['docs'][name]['title'][lang] = fs.readFileSync(x, 'utf-8').match(/^h1 (.+?)\r?\n/)[1]; }); - vars['kebab'] = string => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase(); + vars['kebab'] = (string: string) => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase(); vars['config'] = config; diff --git a/yarn.lock b/yarn.lock index a99e498628..8b12a99c95 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,21 +2,33 @@ # yarn lockfile v1 -"@fortawesome/fontawesome-free-brands@5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free-brands/-/fontawesome-free-brands-5.0.2.tgz#a1cc602eec40a379a3dd8a44c78b31110dd3d3d3" +"@fortawesome/fontawesome-common-types@^0.1.7": + version "0.1.7" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.1.7.tgz#4336c4b06d0b5608ff1215464b66fcf9f4795284" -"@fortawesome/fontawesome-free-regular@5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free-regular/-/fontawesome-free-regular-5.0.2.tgz#429af86bed14689f87648e6322983c65c782c017" +"@fortawesome/fontawesome-free-brands@5.0.13": + version "5.0.13" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free-brands/-/fontawesome-free-brands-5.0.13.tgz#4d15ff4e1e862d5e4a4df3654f8e8acbd47e9c09" + dependencies: + "@fortawesome/fontawesome-common-types" "^0.1.7" -"@fortawesome/fontawesome-free-solid@5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free-solid/-/fontawesome-free-solid-5.0.2.tgz#090ce2c59dd5ec76983f3da8a43e1ab0321b42d5" +"@fortawesome/fontawesome-free-regular@5.0.13": + version "5.0.13" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free-regular/-/fontawesome-free-regular-5.0.13.tgz#eb78c30184e3f456a423a1dcfa0f682f7b50de4a" + dependencies: + "@fortawesome/fontawesome-common-types" "^0.1.7" -"@fortawesome/fontawesome@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome/-/fontawesome-1.0.1.tgz#8ac60e1e7b437889baf9c9d6e3a61ef3b637170d" +"@fortawesome/fontawesome-free-solid@5.0.13": + version "5.0.13" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free-solid/-/fontawesome-free-solid-5.0.13.tgz#24b61aaf471a9d34a5364b052d64a516285ba894" + dependencies: + "@fortawesome/fontawesome-common-types" "^0.1.7" + +"@fortawesome/fontawesome@1.1.8": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome/-/fontawesome-1.1.8.tgz#75fe66a60f95508160bb16bd781ad7d89b280f5b" + dependencies: + "@fortawesome/fontawesome-common-types" "^0.1.7" "@gulp-sourcemaps/identity-map@1.X": version "1.0.1" From 8c40917cc2762a498cd2d35a4f4f69b01de3d672 Mon Sep 17 00:00:00 2001 From: rinsuki <428rinsuki+git@gmail.com> Date: Sun, 17 Jun 2018 19:55:39 +0900 Subject: [PATCH 5/7] [noImplicitAny: true] src/text --- package.json | 3 ++ src/text/html.ts | 5 +-- src/text/parse/core/syntax-highlighter.ts | 13 ++++++-- src/text/parse/elements/bold.ts | 12 +++++-- src/text/parse/elements/code.ts | 13 ++++++-- src/text/parse/elements/emoji.ts | 12 +++++-- src/text/parse/elements/hashtag.ts | 12 +++++-- src/text/parse/elements/inline-code.ts | 13 ++++++-- src/text/parse/elements/link.ts | 14 ++++++-- src/text/parse/elements/mention.ts | 13 ++++++-- src/text/parse/elements/quote.ts | 12 +++++-- src/text/parse/elements/search.ts | 10 ++++-- src/text/parse/elements/title.ts | 12 +++++-- src/text/parse/elements/url.ts | 12 +++++-- src/text/parse/index.ts | 39 +++++++++++++++++++---- yarn.lock | 15 +++++++++ 16 files changed, 166 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index bf49a6599f..2b81b03693 100644 --- a/package.json +++ b/package.json @@ -216,5 +216,8 @@ "websocket": "1.0.26", "ws": "5.2.0", "xev": "2.0.1" + }, + "devDependencies": { + "@types/jsdom": "11.0.5" } } diff --git a/src/text/html.ts b/src/text/html.ts index b55d9b80a7..41adb2e7f7 100644 --- a/src/text/html.ts +++ b/src/text/html.ts @@ -1,7 +1,8 @@ -import { lib as emojilib } from 'emojilib'; +const { lib: emojilib } = require('emojilib'); import { JSDOM } from 'jsdom'; import config from '../config'; import { INote } from '../models/note'; +import { TextElement } from './parse'; const handlers: {[key: string]: (window: any, token: any, mentionedRemoteUsers: INote["mentionedRemoteUsers"]) => void} = { bold({ document }, { bold }) { @@ -90,7 +91,7 @@ const handlers: {[key: string]: (window: any, token: any, mentionedRemoteUsers: } }; -export default (tokens, mentionedRemoteUsers: INote['mentionedRemoteUsers'] = []) => { +export default (tokens: TextElement[], mentionedRemoteUsers: INote['mentionedRemoteUsers'] = []) => { const { window } = new JSDOM(''); for (const token of tokens) { diff --git a/src/text/parse/core/syntax-highlighter.ts b/src/text/parse/core/syntax-highlighter.ts index c0396b1fc6..3fb7a3b73d 100644 --- a/src/text/parse/core/syntax-highlighter.ts +++ b/src/text/parse/core/syntax-highlighter.ts @@ -1,4 +1,4 @@ -function escape(text) { +function escape(text: string) { return text .replace(/>/g, '>') .replace(/ (Token | null); + +const elements: Element[] = [ // comment code => { if (code.substr(0, 2) != '//') return null; @@ -305,7 +312,7 @@ export default (source: string, lang?: string) => { let i = 0; - function push(token) { + function push(token: Token) { html += token.html; code = code.substr(token.next); i += token.next; diff --git a/src/text/parse/elements/bold.ts b/src/text/parse/elements/bold.ts index ce25764457..0566ace8b7 100644 --- a/src/text/parse/elements/bold.ts +++ b/src/text/parse/elements/bold.ts @@ -2,7 +2,13 @@ * Bold */ -module.exports = text => { +export type TextElementBold = { + type: "bold" + content: string + bold: string +}; + +export default function(text: string) { const match = text.match(/^\*\*(.+?)\*\*/); if (!match) return null; const bold = match[0]; @@ -10,5 +16,5 @@ module.exports = text => { type: 'bold', content: bold, bold: bold.substr(2, bold.length - 4) - }; -}; + } as TextElementBold; +} diff --git a/src/text/parse/elements/code.ts b/src/text/parse/elements/code.ts index 4821e95fe2..de87aa410b 100644 --- a/src/text/parse/elements/code.ts +++ b/src/text/parse/elements/code.ts @@ -4,7 +4,14 @@ import genHtml from '../core/syntax-highlighter'; -module.exports = text => { +export type TextElementCode = { + type: "code" + content: string + code: string + html: string +}; + +export default function(text: string) { const match = text.match(/^```([\s\S]+?)```/); if (!match) return null; const code = match[0]; @@ -13,5 +20,5 @@ module.exports = text => { content: code, code: code.substr(3, code.length - 6).trim(), html: genHtml(code.substr(3, code.length - 6).trim()) - }; -}; + } as TextElementCode; +} diff --git a/src/text/parse/elements/emoji.ts b/src/text/parse/elements/emoji.ts index e24231a223..d0eed88965 100644 --- a/src/text/parse/elements/emoji.ts +++ b/src/text/parse/elements/emoji.ts @@ -2,7 +2,13 @@ * Emoji */ -module.exports = text => { +export type TextElementEmoji = { + type: "emoji" + content: string + emoji: string +}; + +export default function(text: string) { const match = text.match(/^:[a-zA-Z0-9+-_]+:/); if (!match) return null; const emoji = match[0]; @@ -10,5 +16,5 @@ module.exports = text => { type: 'emoji', content: emoji, emoji: emoji.substr(1, emoji.length - 2) - }; -}; + } as TextElementEmoji; +} diff --git a/src/text/parse/elements/hashtag.ts b/src/text/parse/elements/hashtag.ts index ee57b140b8..cde0c2b224 100644 --- a/src/text/parse/elements/hashtag.ts +++ b/src/text/parse/elements/hashtag.ts @@ -2,7 +2,13 @@ * Hashtag */ -module.exports = (text, i) => { +export type TextElementHashtag = { + type: "hashtag" + content: string + hashtag: string +}; + +export default function(text: string, i: number) { if (!(/^\s#[^\s]+/.test(text) || (i == 0 && /^#[^\s]+/.test(text)))) return null; const isHead = text[0] == '#'; const hashtag = text.match(/^\s?#[^\s]+/)[0]; @@ -15,5 +21,5 @@ module.exports = (text, i) => { content: isHead ? hashtag : hashtag.substr(1), hashtag: isHead ? hashtag.substr(1) : hashtag.substr(2) }); - return res; -}; + return res as TextElementHashtag[]; +} diff --git a/src/text/parse/elements/inline-code.ts b/src/text/parse/elements/inline-code.ts index 9f9ef51a2b..bcb0bca0ad 100644 --- a/src/text/parse/elements/inline-code.ts +++ b/src/text/parse/elements/inline-code.ts @@ -4,7 +4,14 @@ import genHtml from '../core/syntax-highlighter'; -module.exports = text => { +export type TextElementInlineCode = { + type: "inline-code" + content: string + code: string + html: string +}; + +export default function(text: string) { const match = text.match(/^`(.+?)`/); if (!match) return null; const code = match[0]; @@ -13,5 +20,5 @@ module.exports = text => { content: code, code: code.substr(1, code.length - 2).trim(), html: genHtml(code.substr(1, code.length - 2).trim()) - }; -}; + } as TextElementInlineCode; +} diff --git a/src/text/parse/elements/link.ts b/src/text/parse/elements/link.ts index 35563ddc3d..7e0d6f5cf8 100644 --- a/src/text/parse/elements/link.ts +++ b/src/text/parse/elements/link.ts @@ -2,7 +2,15 @@ * Link */ -module.exports = text => { +export type TextElementLink = { + type: "link" + content: string + title: string + url: string + silent: boolean +}; + +export default function(text: string) { const match = text.match(/^\??\[([^\[\]]+?)\]\((https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.=\+\-]+?)\)/); if (!match) return null; const silent = text[0] == '?'; @@ -15,5 +23,5 @@ module.exports = text => { title: title, url: url, silent: silent - }; -}; + } as TextElementLink; +} diff --git a/src/text/parse/elements/mention.ts b/src/text/parse/elements/mention.ts index 2ad2788300..a4140458d4 100644 --- a/src/text/parse/elements/mention.ts +++ b/src/text/parse/elements/mention.ts @@ -3,7 +3,14 @@ */ import parseAcct from '../../../acct/parse'; -module.exports = text => { +export type TextElementMention = { + type: "mention" + content: string + username: string + host: string +}; + +export default function(text: string) { const match = text.match(/^@[a-z0-9_]+(?:@[a-z0-9\.\-]+[a-z0-9])?/i); if (!match) return null; const mention = match[0]; @@ -13,5 +20,5 @@ module.exports = text => { content: mention, username, host - }; -}; + } as TextElementMention; +} diff --git a/src/text/parse/elements/quote.ts b/src/text/parse/elements/quote.ts index cc8cfffdc4..56de561f3f 100644 --- a/src/text/parse/elements/quote.ts +++ b/src/text/parse/elements/quote.ts @@ -2,7 +2,13 @@ * Quoted text */ -module.exports = text => { +export type TextElementQuote = { + type: "quote" + content: string + quote: string +}; + +export default function(text: string) { const match = text.match(/^"([\s\S]+?)\n"/); if (!match) return null; const quote = match[0]; @@ -10,5 +16,5 @@ module.exports = text => { type: 'quote', content: quote, quote: quote.substr(1, quote.length - 2).trim(), - }; -}; + } as TextElementQuote; +} diff --git a/src/text/parse/elements/search.ts b/src/text/parse/elements/search.ts index 12ee8ecbb8..4bd19ee3fa 100644 --- a/src/text/parse/elements/search.ts +++ b/src/text/parse/elements/search.ts @@ -2,7 +2,13 @@ * Search */ -module.exports = text => { +export type TextElementSearch = { + type: "search" + content: string + query: string +}; + +export default function(text: string) { const match = text.match(/^(.+?) 検索(\n|$)/); if (!match) return null; return { @@ -10,4 +16,4 @@ module.exports = text => { content: match[0], query: match[1] }; -}; +} diff --git a/src/text/parse/elements/title.ts b/src/text/parse/elements/title.ts index 9f4708f5d6..11b3abc61b 100644 --- a/src/text/parse/elements/title.ts +++ b/src/text/parse/elements/title.ts @@ -2,7 +2,13 @@ * Title */ -module.exports = text => { +export type TextElementTitle = { + type: "title" + content: string + title: string +}; + +export default function(text: string) { const match = text.match(/^【(.+?)】\n/); if (!match) return null; const title = match[0]; @@ -10,5 +16,5 @@ module.exports = text => { type: 'title', content: title, title: title.substr(1, title.length - 3) - }; -}; + } as TextElementTitle; +} diff --git a/src/text/parse/elements/url.ts b/src/text/parse/elements/url.ts index 1003aff9c3..bbc27b4fd7 100644 --- a/src/text/parse/elements/url.ts +++ b/src/text/parse/elements/url.ts @@ -2,7 +2,13 @@ * URL */ -module.exports = text => { +export type TextElementUrl = { + type: "url" + content: string + url: string +}; + +export default function(text: string) { const match = text.match(/^https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.=\+\-]+/); if (!match) return null; const url = match[0]; @@ -10,5 +16,5 @@ module.exports = text => { type: 'url', content: url, url: url - }; -}; + } as TextElementUrl; +} diff --git a/src/text/parse/index.ts b/src/text/parse/index.ts index cfddd9f615..ccfef44591 100644 --- a/src/text/parse/index.ts +++ b/src/text/parse/index.ts @@ -2,6 +2,18 @@ * Misskey Text Analyzer */ +import { TextElementBold } from "./elements/bold"; +import { TextElementCode } from "./elements/code"; +import { TextElementEmoji } from "./elements/emoji"; +import { TextElementHashtag } from "./elements/hashtag"; +import { TextElementInlineCode } from "./elements/inline-code"; +import { TextElementLink } from "./elements/link"; +import { TextElementMention } from "./elements/mention"; +import { TextElementQuote } from "./elements/quote"; +import { TextElementSearch } from "./elements/search"; +import { TextElementTitle } from "./elements/title"; +import { TextElementUrl } from "./elements/url"; + const elements = [ require('./elements/bold'), require('./elements/title'), @@ -14,17 +26,31 @@ const elements = [ require('./elements/quote'), require('./elements/emoji'), require('./elements/search') -]; +].map(element => element.default as TextElementProcessor); -export default (source: string): any[] => { +export type TextElement = {type: "text", content: string} + | TextElementBold + | TextElementCode + | TextElementEmoji + | TextElementHashtag + | TextElementInlineCode + | TextElementLink + | TextElementMention + | TextElementQuote + | TextElementSearch + | TextElementTitle + | TextElementUrl; +export type TextElementProcessor = (text: string, i: number) => TextElement | TextElement[]; + +export default (source: string): TextElement[] => { if (source == '') { return null; } - const tokens = []; + const tokens: TextElement[] = []; - function push(token) { + function push(token: TextElement) { if (token != null) { tokens.push(token); source = source.substr(token.content.length); @@ -59,9 +85,8 @@ export default (source: string): any[] => { } // テキストを纏める - tokens[0] = [tokens[0]]; return tokens.reduce((a, b) => { - if (a[a.length - 1].type == 'text' && b.type == 'text') { + if (a.length && a[a.length - 1].type == 'text' && b.type == 'text') { const tail = a.pop(); return a.concat({ type: 'text', @@ -70,5 +95,5 @@ export default (source: string): any[] => { } else { return a.concat(b); } - }); + }, [] as TextElement[]); }; diff --git a/yarn.lock b/yarn.lock index 8b12a99c95..e4a53091e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -277,6 +277,15 @@ version "3.11.1" resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.11.1.tgz#ac5bab26be5f9c6f74b6b23420f2cfa5a7a6ba40" +"@types/jsdom@11.0.5": + version "11.0.5" + resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-11.0.5.tgz#b12fffc73eb3731b218e9665a50f023b6b84b5cb" + dependencies: + "@types/events" "*" + "@types/node" "*" + "@types/tough-cookie" "*" + parse5 "^3.0.2" + "@types/keygrip@*": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.1.tgz#ff540462d2fb4d0a88441ceaf27d287b01c3d878" @@ -8221,6 +8230,12 @@ parse5@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" +parse5@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" + dependencies: + "@types/node" "*" + parseurl@^1.3.0, parseurl@~1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" From 9d65415fdc4cab84945040f59cae3047077d8fc7 Mon Sep 17 00:00:00 2001 From: rinsuki <428rinsuki+git@gmail.com> Date: Sun, 17 Jun 2018 19:59:02 +0900 Subject: [PATCH 6/7] [noImplicitAny: true] src/services/note --- src/services/note/create.ts | 4 ++-- src/services/note/reaction/create.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/note/create.ts b/src/services/note/create.ts index 98415b8971..ef03c4e044 100644 --- a/src/services/note/create.ts +++ b/src/services/note/create.ts @@ -33,7 +33,7 @@ class NotificationManager { reason: Reason; }> = []; - constructor(user, note) { + constructor(user: IUser, note: any) { this.user = user; this.note = note; } @@ -451,7 +451,7 @@ export default async (user: IUser, data: { // $ne: note._id // } //}); - const existRenote = null; + const existRenote: INote | null = null; //#endregion if (!existRenote) { diff --git a/src/services/note/reaction/create.ts b/src/services/note/reaction/create.ts index 123c091c85..5b30bb5e15 100644 --- a/src/services/note/reaction/create.ts +++ b/src/services/note/reaction/create.ts @@ -36,7 +36,7 @@ export default async (user: IUser, note: INote, reaction: string) => new Promise res(); - const inc = {}; + const inc: {[key: string]: number} = {}; inc[`reactionCounts.${reaction}`] = 1; // Increment reactions count From daa409cd8285633427ffb3a89d3296824365e918 Mon Sep 17 00:00:00 2001 From: rinsuki <428rinsuki+git@gmail.com> Date: Sun, 17 Jun 2018 20:04:19 +0900 Subject: [PATCH 7/7] [noImplicitAny: true] src/services/drive --- package.json | 1 + src/services/drive/add-file.ts | 8 ++++---- src/services/drive/upload-from-url.ts | 4 +++- yarn.lock | 6 ++++++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 2b81b03693..6691723386 100644 --- a/package.json +++ b/package.json @@ -218,6 +218,7 @@ "xev": "2.0.1" }, "devDependencies": { + "@types/file-type": "5.2.1", "@types/jsdom": "11.0.5" } } diff --git a/src/services/drive/add-file.ts b/src/services/drive/add-file.ts index d7f71e8665..4167df0662 100644 --- a/src/services/drive/add-file.ts +++ b/src/services/drive/add-file.ts @@ -7,7 +7,7 @@ import * as crypto from 'crypto'; import * as _gm from 'gm'; import * as debug from 'debug'; import fileType = require('file-type'); -import prominence = require('prominence'); +const prominence = require('prominence'); import DriveFile, { IMetadata, getDriveFileBucket, IDriveFile } from '../../models/drive-file'; import DriveFolder from '../../models/drive-folder'; @@ -33,7 +33,7 @@ const writeChunks = (name: string, readable: stream.Readable, type: string, meta readable.pipe(writeStream); })); -const writeThumbnailChunks = (name: string, readable: stream.Readable, originalId) => +const writeThumbnailChunks = (name: string, readable: stream.Readable, originalId: mongodb.ObjectID) => getDriveFileThumbnailBucket() .then(bucket => new Promise((resolve, reject) => { const writeStream = bucket.openUploadStream(name, { @@ -89,7 +89,7 @@ export default async function( const calcHash = new Promise((res, rej) => { const readable = fs.createReadStream(path); const hash = crypto.createHash('md5'); - const chunks = []; + const chunks: Buffer[] = []; readable .on('error', rej) .pipe(hash) @@ -201,7 +201,7 @@ export default async function( return driveFolder; }; - const properties = {}; + const properties: {[key: string]: any} = {}; let propPromises: Array> = []; diff --git a/src/services/drive/upload-from-url.ts b/src/services/drive/upload-from-url.ts index e216ca603d..f83d57d415 100644 --- a/src/services/drive/upload-from-url.ts +++ b/src/services/drive/upload-from-url.ts @@ -8,10 +8,12 @@ import * as request from 'request'; import { IDriveFile, validateFileName } from '../../models/drive-file'; import create from './add-file'; import config from '../../config'; +import { IUser } from '../../models/user'; +import * as mongodb from "mongodb"; const log = debug('misskey:drive:upload-from-url'); -export default async (url: string, user, folderId = null, uri: string = null): Promise => { +export default async (url: string, user: IUser, folderId: mongodb.ObjectID = null, uri: string = null): Promise => { log(`REQUESTED: ${url}`); let name = URL.parse(url).pathname.split('/').pop(); diff --git a/yarn.lock b/yarn.lock index e4a53091e5..cb6a4a6221 100644 --- a/yarn.lock +++ b/yarn.lock @@ -176,6 +176,12 @@ version "1.3.0" resolved "https://registry.yarnpkg.com/@types/fancy-log/-/fancy-log-1.3.0.tgz#a61ab476e5e628cd07a846330df53b85e05c8ce0" +"@types/file-type@5.2.1": + version "5.2.1" + resolved "https://registry.yarnpkg.com/@types/file-type/-/file-type-5.2.1.tgz#e7af49e08187b6b7598509c5e416669d25fa3461" + dependencies: + "@types/node" "*" + "@types/form-data@*": version "2.2.1" resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e"