diff --git a/lib/hexo/index.ts b/lib/hexo/index.ts index edffd471a3..a7dd75df18 100644 --- a/lib/hexo/index.ts +++ b/lib/hexo/index.ts @@ -37,7 +37,7 @@ import loadDatabase from './load_database'; import multiConfigPath from './multi_config_path'; import { deepMerge, full_url_for } from 'hexo-util'; import type Box from '../box'; -import type { NodeJSLikeCallback } from '../types'; +import type { AssetGenerator, LocalsType, NodeJSLikeCallback, NormalPageGenerator, NormalPostGenerator, PageGenerator, PostGenerator, SiteLocals } from '../types'; let resolveSync; // = require('resolve'); @@ -50,7 +50,8 @@ const routeCache = new WeakMap(); const castArray = (obj: any) => { return Array.isArray(obj) ? obj : [obj]; }; -const mergeCtxThemeConfig = ctx => { +// eslint-disable-next-line no-use-before-define +const mergeCtxThemeConfig = (ctx: Hexo) => { // Merge hexo.config.theme_config into hexo.theme.config before post rendering & generating // config.theme_config has "_config.[theme].yml" merged in load_theme_config.js if (ctx.config.theme_config) { @@ -58,11 +59,12 @@ const mergeCtxThemeConfig = ctx => { } }; -const createLoadThemeRoute = function(generatorResult, locals, ctx) { +// eslint-disable-next-line no-use-before-define +const createLoadThemeRoute = function(generatorResult: NormalPageGenerator | NormalPostGenerator, locals: LocalsType, ctx: Hexo) { const { log, theme } = ctx; const { path, cache: useCache } = locals; - const layout = [...new Set(castArray(generatorResult.layout))]; + const layout: string[] = [...new Set(castArray(generatorResult.layout))]; const layoutLength = layout.length; // always use cache in fragment_cache @@ -96,7 +98,7 @@ const createLoadThemeRoute = function(generatorResult, locals, ctx) { }; }; -function debounce(func: () => void, wait: number) { +function debounce(func: () => void, wait: number): () => void { let timeout: NodeJS.Timeout; return function() { clearTimeout(timeout); @@ -342,9 +344,11 @@ class Hexo extends EventEmitter { }); } - call(name: string, args: any, callback?: NodeJSLikeCallback) { + call(name: string, callback?: NodeJSLikeCallback): Promise; + call(name: string, args: object, callback?: NodeJSLikeCallback): Promise; + call(name: string, args?: object | NodeJSLikeCallback, callback?: NodeJSLikeCallback): Promise { if (!callback && typeof args === 'function') { - callback = args; + callback = args as NodeJSLikeCallback; args = {}; } @@ -378,7 +382,7 @@ class Hexo extends EventEmitter { loadPlugin(path: string, callback?: NodeJSLikeCallback): Promise { return readFile(path).then(script => { - // Based on: https://github.com/joyent/node/blob/v0.10.33/src/node.js#L516 + // Based on: https://github.com/nodejs/node-v0.x-archive/blob/v0.10.33/src/node.js#L516 const module = new Module(path); module.filename = path; module.paths = Module._nodeModulePaths(path); @@ -468,12 +472,10 @@ class Hexo extends EventEmitter { _generateLocals() { const { config, env, theme, theme_dir } = this; const ctx = { config: { url: this.config.url } }; - const localsObj = this.locals.toObject(); + const localsObj = this.locals.toObject() as SiteLocals; class Locals { - page: { - path: string; - }; + page: NormalPageGenerator | NormalPostGenerator; path: string; url: string; config: object; @@ -481,10 +483,10 @@ class Hexo extends EventEmitter { layout: string; env: any; view_dir: string; - site: object; + site: SiteLocals; cache?: boolean; - constructor(path: string, locals) { + constructor(path: string, locals: NormalPageGenerator | NormalPostGenerator) { this.page = { ...locals }; if (this.page.path == null) this.page.path = path; this.path = path; @@ -501,9 +503,9 @@ class Hexo extends EventEmitter { return Locals; } - _runGenerators(): Promise { + _runGenerators(): Promise<(AssetGenerator | PostGenerator | PageGenerator)[]> { this.locals.invalidate(); - const siteLocals = this.locals.toObject(); + const siteLocals = this.locals.toObject() as SiteLocals; const generators = this.extend.generator.list(); const { log } = this; @@ -518,17 +520,19 @@ class Hexo extends EventEmitter { }, []); } - _routerRefresh(runningGenerators: Promise, useCache: boolean): Promise { + _routerRefresh(runningGenerators: Promise<(AssetGenerator | PostGenerator | PageGenerator)[]>, useCache: boolean): Promise { const { route } = this; const routeList = route.list(); const Locals = this._generateLocals(); Locals.prototype.cache = useCache; - return runningGenerators.map(generatorResult => { + return runningGenerators.map((generatorResult: AssetGenerator | PostGenerator | PageGenerator) => { if (typeof generatorResult !== 'object' || generatorResult.path == null) return undefined; // add Route const path = route.format(generatorResult.path); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore const { data, layout } = generatorResult; if (!layout) { @@ -536,8 +540,8 @@ class Hexo extends EventEmitter { return path; } - return this.execFilter('template_locals', new Locals(path, data), { context: this }) - .then(locals => { route.set(path, createLoadThemeRoute(generatorResult, locals, this)); }) + return this.execFilter('template_locals', new Locals(path, data as unknown as NormalPageGenerator | NormalPostGenerator), { context: this }) + .then(locals => { route.set(path, createLoadThemeRoute(generatorResult as NormalPageGenerator | NormalPostGenerator, locals, this)); }) .thenReturn(path); }).then(newRouteList => { // Remove old routes diff --git a/lib/plugins/filter/template_locals/i18n.ts b/lib/plugins/filter/template_locals/i18n.ts index 9c5759c01b..87c505280b 100644 --- a/lib/plugins/filter/template_locals/i18n.ts +++ b/lib/plugins/filter/template_locals/i18n.ts @@ -1,18 +1,8 @@ import { Pattern } from 'hexo-util'; import type Hexo from '../../../hexo'; +import type { LocalsType } from '../../../types'; -interface Locals { - path: string; - page: { - lang: string; - language: string; - canonical_path: string; - }; - __: (key: string) => string; - _p: (key: string, options?: any) => string; -} - -function i18nLocalsFilter(this: Hexo, locals: Locals): void { +function i18nLocalsFilter(this: Hexo, locals: LocalsType): void { const { i18n } = this.theme; const { config } = this; const i18nDir = config.i18n_dir; diff --git a/lib/plugins/generator/asset.ts b/lib/plugins/generator/asset.ts index 074f497620..336c4e2612 100644 --- a/lib/plugins/generator/asset.ts +++ b/lib/plugins/generator/asset.ts @@ -5,6 +5,7 @@ import { extname } from 'path'; import { magenta } from 'picocolors'; import type warehouse from 'warehouse'; import type Hexo from '../../hexo'; +import type { AssetGenerator } from '../../types'; interface Data { modified: boolean; @@ -36,7 +37,7 @@ const process = (name: string, ctx: Hexo) => { data.data = () => ctx.render.render({ path: source, toString: true - }).catch(err => { + }).catch((err: Error) => { ctx.log.error({err}, 'Asset render failed: %s', magenta(path)); }); } else { @@ -47,7 +48,7 @@ const process = (name: string, ctx: Hexo) => { }); }; -function assetGenerator(this: Hexo): Promise { +function assetGenerator(this: Hexo): Promise { return Promise.all([ process('Asset', this), process('PostAsset', this) diff --git a/lib/plugins/generator/page.ts b/lib/plugins/generator/page.ts index 8dbbcd817c..da2cf08c8b 100644 --- a/lib/plugins/generator/page.ts +++ b/lib/plugins/generator/page.ts @@ -1,5 +1,7 @@ -function pageGenerator(locals) { - return locals.pages.map(page => { +import type { PageGenerator, PageSchema, SiteLocals } from '../../types'; + +function pageGenerator(locals: SiteLocals): PageGenerator[] { + return locals.pages.map((page: PageSchema) => { const { path, layout } = page; if (!layout || layout === 'false' || layout === 'off') { diff --git a/lib/plugins/generator/post.ts b/lib/plugins/generator/post.ts index 4deec563dd..d97030b04f 100644 --- a/lib/plugins/generator/post.ts +++ b/lib/plugins/generator/post.ts @@ -1,8 +1,10 @@ -function postGenerator(locals) { +import type { PostGenerator, PostSchema, SiteLocals } from '../../types'; + +function postGenerator(locals: SiteLocals): PostGenerator[] { const posts = locals.posts.sort('-date').toArray(); const { length } = posts; - return posts.map((post, i) => { + return posts.map((post: PostSchema, i: number) => { const { path, layout } = post; if (!layout || layout === 'false') { diff --git a/lib/plugins/helper/date.ts b/lib/plugins/helper/date.ts index 8d45b27147..063a437cb4 100644 --- a/lib/plugins/helper/date.ts +++ b/lib/plugins/helper/date.ts @@ -1,7 +1,7 @@ import moment from 'moment-timezone'; const { isMoment } = moment; import moize from 'moize'; -import type Hexo from '../../hexo'; +import type { LocalsType } from '../../types'; const isDate = (value: moment.MomentInput | moment.Moment): boolean => typeof value === 'object' && value instanceof Date && !isNaN(value.getTime()); @@ -61,7 +61,7 @@ function timeTagHelper(date: string | number | Date | moment.Moment, format: str return ``; } -function getLanguage(ctx) { +function getLanguage(ctx: LocalsType) { return ctx.page.lang || ctx.page.language || ctx.config.language; } diff --git a/lib/plugins/helper/is.ts b/lib/plugins/helper/is.ts index 1f843cf3ff..ef9ec0fc46 100644 --- a/lib/plugins/helper/is.ts +++ b/lib/plugins/helper/is.ts @@ -1,4 +1,4 @@ -function isCurrentHelper(path = '/', strict) { +function isCurrentHelper(path = '/', strict: boolean) { const currentPath = this.path.replace(/^[^/].*/, '/$&'); if (strict) { diff --git a/lib/plugins/injector/index.ts b/lib/plugins/injector/index.ts index 6736417bc8..4c640279c1 100644 --- a/lib/plugins/injector/index.ts +++ b/lib/plugins/injector/index.ts @@ -1,6 +1,6 @@ import type Hexo from '../../hexo'; export = (ctx: Hexo) => { - // eslint-disable-next-line no-unused-vars + // eslint-disable-next-line @typescript-eslint/no-unused-vars const { injector } = ctx.extend; }; diff --git a/lib/theme/view.ts b/lib/theme/view.ts index 9600d8be83..e96d2f0538 100644 --- a/lib/theme/view.ts +++ b/lib/theme/view.ts @@ -25,7 +25,7 @@ class Options { class View { public path: string; - public source: any; + public source: string; public _theme: Theme; public data: any; public _compiled: any; @@ -89,6 +89,7 @@ class View { } _buildLocals(locals: Options) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars const { layout, _content, ...data } = this.data; return assignIn({}, locals, data, { filename: this.source diff --git a/lib/types.ts b/lib/types.ts index 509686011c..6959a456cc 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,4 +1,5 @@ import moment from 'moment'; +import type default_config from './hexo/default_config'; export type NodeJSLikeCallback = (err: E, result?: R) => void @@ -14,6 +15,7 @@ export interface RenderData { more?: string; } +// Schema export interface PostSchema { id?: string; _id?: string; @@ -39,4 +41,89 @@ export interface PostSchema { categories?: any; tags?: any; __permalink?: string; + __post?: boolean; + canonical_path?: string; + lang?: string; + language?: string; + prev?: PostSchema; + next?: PostSchema; +} + +export interface PageSchema { + _id?: string; + title?: string; + date?: moment.Moment, + updated?: moment.Moment, + comments?: boolean; + layout?: string; + _content?: string; + source?: string; + path?: string; + raw?: string; + content?: string; + excerpt?: string; + more?: string; + author?: string; + full_source?: string; + permalink?: string; + tags?: any; + canonical_path?: string; + lang?: string; + language?: string; + __page?: boolean; +} + +export interface LocalsType { + page: PostSchema | PageSchema; + path: string; + url: string; + config: typeof default_config; + theme: object; + layout: string; + env: any; + view_dir: string; + site: object; + cache?: boolean; + __?: (key: string) => string; + _p?: (key: string, options?: any) => string; +} + +// Generator return types +export interface AssetGenerator { + path: string; + data: { + modified: boolean; + data?: () => any; + } +} + +export type SimplePostGenerator = { + path: string; + data: string; +} +export type NormalPostGenerator = { + path: string; + layout: string[]; + data: PostSchema; +} +export type PostGenerator = SimplePostGenerator | NormalPostGenerator; + + +export type SimplePageGenerator = { + path: string; + data: string; +} +export type NormalPageGenerator = { + path: string; + layout: string[]; + data: PageSchema; +} +export type PageGenerator = SimplePageGenerator | NormalPageGenerator; + +export interface SiteLocals { + posts: any; // _Query + pages: any; // _Query + categories: any; // _Model + tags: any; // _Model + data: object; }