diff --git a/.eslintrc.json b/.eslintrc.json index 6be9a4c7cc..d82fdaa6b1 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,5 +4,8 @@ "parserOptions": { "sourceType": "module", "ecmaVersion": 2020 + }, + "rules": { + "@typescript-eslint/no-explicit-any": 0 } } diff --git a/lib/box/file.ts b/lib/box/file.ts index ce5da96658..82cfc257c0 100644 --- a/lib/box/file.ts +++ b/lib/box/file.ts @@ -5,6 +5,10 @@ class File { public path: any; public params: any; public type: any; + static TYPE_CREATE: 'create'; + static TYPE_UPDATE: 'update'; + static TYPE_SKIP: 'skip'; + static TYPE_DELETE: 'delete'; constructor({ source, path, params, type }) { this.source = source; diff --git a/lib/box/index.ts b/lib/box/index.ts index 40dc07b85f..9c65efef72 100644 --- a/lib/box/index.ts +++ b/lib/box/index.ts @@ -1,5 +1,5 @@ import {join, sep} from 'path'; -import Promise from 'bluebird'; +import BlueBirdPromise from 'bluebird'; import File from './file'; import {Pattern, createSha1Hash} from 'hexo-util'; import {createReadStream, readdir, stat, watch} from 'hexo-fs'; @@ -9,21 +9,27 @@ import {isMatch, makeRe} from 'micromatch'; const defaultPattern = new Pattern(() => ({})); +interface Processor { + pattern: Pattern; + process: (file: File) => void; +} + class Box extends EventEmitter { public options: any; public context: any; public base: any; - public processors: any; + public processors: Processor[]; public _processingFiles: any; public watcher: any; public Cache: any; + // TODO: replace runtime class _File public File: any; public ignore: any; public source: any; public emit: any; public ctx: any; - constructor(ctx, base, options) { + constructor(ctx, base, options?: object) { super(); this.options = Object.assign({ @@ -51,10 +57,13 @@ class Box extends EventEmitter { this.ignore = targets; this.options.ignored = targets.map(s => toRegExp(ctx, s)).filter(x => x); } + _createFileClass() { const ctx = this.context; class _File extends File { + public box: Box; + render(options) { return ctx.render.render({ path: this.source @@ -132,7 +141,7 @@ class Box extends EventEmitter { _processFile(type, path) { if (this._processingFiles[path]) { - return Promise.resolve(); + return BlueBirdPromise.resolve(); } this._processingFiles[path] = true; @@ -144,7 +153,7 @@ class Box extends EventEmitter { path }); - return Promise.reduce(this.processors, (count, processor) => { + return BlueBirdPromise.reduce(this.processors, (count, processor) => { const params = processor.pattern.match(path); if (!params) return count; @@ -155,7 +164,7 @@ class Box extends EventEmitter { type }); - return Reflect.apply(Promise.method(processor.process), ctx, [file]) + return Reflect.apply(BlueBirdPromise.method(processor.process), ctx, [file]) .thenReturn(count + 1); }, 0).then(count => { if (count) { @@ -175,7 +184,7 @@ class Box extends EventEmitter { watch(callback) { if (this.isWatching()) { - return Promise.reject(new Error('Watcher has already started.')).asCallback(callback); + return BlueBirdPromise.reject(new Error('Watcher has already started.')).asCallback(callback); } const { base } = this; @@ -229,7 +238,7 @@ function getHash(path) { const src = createReadStream(path); const hasher = createSha1Hash(); - const finishedPromise = new Promise((resolve, reject) => { + const finishedPromise = new BlueBirdPromise((resolve, reject) => { src.once('error', reject); src.once('end', resolve); }); @@ -258,9 +267,9 @@ function isIgnoreMatch(path, ignore) { } function readDirWalker(ctx, base, results, ignore, prefix) { - if (isIgnoreMatch(base, ignore)) return Promise.resolve(); + if (isIgnoreMatch(base, ignore)) return BlueBirdPromise.resolve(); - return Promise.map(readdir(base).catch(err => { + return BlueBirdPromise.map(readdir(base).catch(err => { ctx.log.error({ err }, 'Failed to read directory: %s', base); if (err && err.code === 'ENOENT') return []; throw err; diff --git a/lib/hexo/index.ts b/lib/hexo/index.ts index e176294e14..c6c98b1946 100644 --- a/lib/hexo/index.ts +++ b/lib/hexo/index.ts @@ -7,7 +7,7 @@ import {EventEmitter} from 'events'; import {readFile} from 'hexo-fs'; import Module from 'module'; import {runInThisContext} from 'vm'; -import {version} from '../../package.json'; +const {version} = require('../../package.json'); import logger from 'hexo-log'; import { @@ -105,6 +105,15 @@ function debounce(func, wait) { }; } +interface Args { + debug?: any; + safe?: any; + silent?: any; + _?: any[]; + output?: any; + config?: any; +} + class Hexo extends EventEmitter { public base_dir: any; public public_dir: any; @@ -143,7 +152,7 @@ class Hexo extends EventEmitter { public alias: any; public data: any; - constructor(base = process.cwd(), args = {}) { + constructor(base = process.cwd(), args: Args = {}) { super(); this.base_dir = base + sep; diff --git a/lib/hexo/post.ts b/lib/hexo/post.ts index 967da8b349..1215b5aefa 100644 --- a/lib/hexo/post.ts +++ b/lib/hexo/post.ts @@ -218,6 +218,18 @@ const createAssetFolder = (path, assetFolder) => { }); }; +interface Result { + path?: string; + content?: string; +} + +interface Data { + engine?: string; + content?: string; + disableNunjucks?: boolean; + markdown?: object; +} + class Post { public context: any; public config: any; @@ -329,7 +341,7 @@ class Post { data.slug = slug; const regex = new RegExp(`^${escapeRegExp(slug)}(?:[^\\/\\\\]+)`); let src = ''; - const result = {}; + const result: Result = {}; data.layout = (data.layout || config.default_layout).toLowerCase(); @@ -367,7 +379,7 @@ class Post { }).thenReturn(result).asCallback(callback); } - render(source, data = {}, callback) { + render(source, data: Data = {}, callback) { const ctx = this.context; const { config } = ctx; const { tag } = ctx.extend; diff --git a/lib/hexo/router.ts b/lib/hexo/router.ts index d593560800..793e90a462 100644 --- a/lib/hexo/router.ts +++ b/lib/hexo/router.ts @@ -3,14 +3,19 @@ import Promise from 'bluebird'; import Stream from 'stream'; const { Readable } = Stream; +interface Data { + data: any; + modified: boolean; +} + class RouteStream extends Readable { public _data: any; - public _ended: any; + public _ended: boolean; public modified: any; public push: any; public emit: any; - constructor(data) { + constructor(data: Data) { super({ objectMode: true }); this._data = data.data; @@ -75,7 +80,7 @@ class RouteStream extends Readable { } } -const _format = path => { +const _format = (path: string) => { path = path || ''; if (typeof path !== 'string') throw new TypeError('path must be a string!'); @@ -93,7 +98,9 @@ const _format = path => { }; class Router extends EventEmitter { - public routes: any; + public routes: { + [key: string]: Data | null; + }; public emit: any; constructor() { @@ -107,11 +114,11 @@ class Router extends EventEmitter { return Object.keys(routes).filter(key => routes[key]); } - format(path) { + format(path: string) { return _format(path); } - get(path) { + get(path: string) { if (typeof path !== 'string') throw new TypeError('path must be a string!'); const data = this.routes[this.format(path)]; @@ -131,7 +138,7 @@ class Router extends EventEmitter { if (typeof path !== 'string') throw new TypeError('path must be a string!'); if (data == null) throw new TypeError('data is required!'); - let obj; + let obj: Data; if (typeof data === 'object' && data.data != null) { obj = data; diff --git a/lib/theme/view.ts b/lib/theme/view.ts index 96ab6ac209..422647ea21 100644 --- a/lib/theme/view.ts +++ b/lib/theme/view.ts @@ -16,6 +16,10 @@ const assignIn = (target, ...sources) => { return target; }; +class Options { + layout?: any; +} + class View { public path: any; public source: any; @@ -36,13 +40,13 @@ class View { this._precompile(); } - render(options = {}, callback) { + render(options: Options | Function = {}, callback) { if (!callback && typeof options === 'function') { callback = options; options = {}; } const { data } = this; - const { layout = options.layout } = data; + const { layout = (options as Options).layout } = data; const locals = this._buildLocals(options); return this._compiled(this._bindHelpers(locals)).then(result => { @@ -61,7 +65,7 @@ class View { }).asCallback(callback); } - renderSync(options = {}) { + renderSync(options: Options = {}) { const { data } = this; const { layout = options.layout } = data; const locals = this._buildLocals(options);