From 88e252d78b704f60ae064b79171cb431ae7ffe3e Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Sun, 28 Apr 2024 23:11:16 +0800 Subject: [PATCH 01/10] refactor: refactor types --- lib/box/file.ts | 26 +++++- lib/box/index.ts | 19 ++-- lib/models/asset.ts | 3 +- lib/models/cache.ts | 21 +++-- lib/models/category.ts | 15 +-- lib/models/page.ts | 5 +- lib/models/post.ts | 45 ++++----- lib/models/post_asset.ts | 5 +- lib/models/tag.ts | 15 +-- lib/plugins/filter/new_post_path.ts | 2 +- lib/plugins/processor/post.ts | 3 +- lib/types.ts | 137 ++++++++++++++++++---------- package.json | 2 + 13 files changed, 188 insertions(+), 110 deletions(-) diff --git a/lib/box/file.ts b/lib/box/file.ts index 30d71cdddf..6515a74582 100644 --- a/lib/box/file.ts +++ b/lib/box/file.ts @@ -3,16 +3,38 @@ import { readFile, readFileSync, stat, statSync, type ReadFileOptions } from 'he import type fs from 'fs'; class File { + + /** + * Full path of the file + */ public source: string; + + /** + * Relative path to the box of the file + */ public path: string; + + /** + * The information from path matching. + */ public params: any; - public type: string; + + /** + * File type. The value can be create, update, skip, delete. + */ + // eslint-disable-next-line no-use-before-define + public type: typeof File.TYPE_CREATE | typeof File.TYPE_UPDATE | typeof File.TYPE_SKIP | typeof File.TYPE_DELETE; static TYPE_CREATE: 'create'; static TYPE_UPDATE: 'update'; static TYPE_SKIP: 'skip'; static TYPE_DELETE: 'delete'; - constructor({ source, path, params, type }) { + constructor({ source, path, params, type }: { + source: string; + path: string; + params: any; + type: typeof File.TYPE_CREATE | typeof File.TYPE_UPDATE | typeof File.TYPE_SKIP | typeof File.TYPE_DELETE; + }) { this.source = source; this.path = path; this.params = params; diff --git a/lib/box/index.ts b/lib/box/index.ts index d2cbf7022b..dd892d8dff 100644 --- a/lib/box/index.ts +++ b/lib/box/index.ts @@ -8,6 +8,7 @@ import { EventEmitter } from 'events'; import { isMatch, makeRe } from 'micromatch'; import type Hexo from '../hexo'; import type { NodeJSLikeCallback } from '../types'; +import type fs from 'fs'; const defaultPattern = new Pattern(() => ({})); @@ -101,7 +102,7 @@ class Box extends EventEmitter { _readDir(base: string, prefix = ''): BlueBirdPromise { const { context: ctx } = this; - const results = []; + const results: string[] = []; return readDirWalker(ctx, base, results, this.ignore, prefix) .return(results) .map(path => this._checkFileStatus(path)) @@ -267,30 +268,30 @@ function toRegExp(ctx: Hexo, arg: string): RegExp | null { return result; } -function isIgnoreMatch(path: string, ignore: string | any[]): boolean { +function isIgnoreMatch(path: string, ignore: string | string[]): boolean { return path && ignore && ignore.length && isMatch(path, ignore); } -function readDirWalker(ctx: Hexo, base: string, results: any[], ignore: any, prefix: string): BlueBirdPromise { +function readDirWalker(ctx: Hexo, base: string, results: string[], ignore: string | string[], prefix: string): BlueBirdPromise { if (isIgnoreMatch(base, ignore)) return BlueBirdPromise.resolve(); 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; - }), async path => { - const fullpath = join(base, path); - const stats = await stat(fullpath).catch(err => { - ctx.log.error({ err }, 'Failed to stat file: %s', fullpath); + }), async (path: string) => { + const fullPath = join(base, path); + const stats: fs.Stats = await stat(fullPath).catch(err => { + ctx.log.error({ err }, 'Failed to stat file: %s', fullPath); if (err && err.code === 'ENOENT') return null; throw err; }); const prefixPath = `${prefix}${path}`; if (stats) { if (stats.isDirectory()) { - return readDirWalker(ctx, fullpath, results, ignore, prefixPath + sep); + return readDirWalker(ctx, fullPath, results, ignore, prefixPath + sep); } - if (!isIgnoreMatch(fullpath, ignore)) { + if (!isIgnoreMatch(fullPath, ignore)) { results.push(prefixPath); } } diff --git a/lib/models/asset.ts b/lib/models/asset.ts index 5a761192da..3520bad85a 100644 --- a/lib/models/asset.ts +++ b/lib/models/asset.ts @@ -1,6 +1,7 @@ import warehouse from 'warehouse'; import { join } from 'path'; import type Hexo from '../hexo'; +import type { AssetSchema } from '../types'; export = (ctx: Hexo) => { const Asset = new warehouse.Schema({ @@ -10,7 +11,7 @@ export = (ctx: Hexo) => { renderable: {type: Boolean, default: true} }); - Asset.virtual('source').get(function() { + Asset.virtual('source').get(function(this: AssetSchema) { return join(ctx.base_dir, this._id); }); diff --git a/lib/models/cache.ts b/lib/models/cache.ts index 60db5ce1c4..6d88dc17ab 100644 --- a/lib/models/cache.ts +++ b/lib/models/cache.ts @@ -1,6 +1,10 @@ import warehouse from 'warehouse'; import Promise from 'bluebird'; import type Hexo from '../hexo'; +import type fs from 'fs'; +import type Model from 'warehouse/dist/model'; +import type Document from 'warehouse/dist/document'; +import type { CacheSchema } from '../types'; export = (ctx: Hexo) => { const Cache = new warehouse.Schema({ @@ -9,13 +13,15 @@ export = (ctx: Hexo) => { modified: {type: Number, default: Date.now() } // UnixTime }); - Cache.static('compareFile', function(id, hashFn, statFn) { - const cache = this.findById(id); + Cache.static('compareFile', function(this: Model, id: string, + hashFn: (id: string) => Promise, + statFn: (id: string) => Promise): Promise<{ type: string }> { + const cache = this.findById(id) as Document; // If cache does not exist, then it must be a new file. We have to get both // file hash and stats. if (!cache) { - return Promise.all([hashFn(id), statFn(id)]).spread((hash, stats) => this.insert({ + return Promise.all([hashFn(id), statFn(id)]).spread((hash: string, stats: fs.Stats) => this.insert({ _id: id, hash, modified: stats.mtime.getTime() @@ -24,10 +30,10 @@ export = (ctx: Hexo) => { }); } - let mtime; + let mtime: number; // Get file stats - return statFn(id).then(stats => { + return statFn(id).then(stats => { mtime = stats.mtime.getTime(); // Skip the file if the modified time is unchanged @@ -39,7 +45,7 @@ export = (ctx: Hexo) => { // Get file hash return hashFn(id); - }).then(result => { + }).then((result: string | object) => { // If the result is an object, skip the following steps because it's an // unchanged file if (typeof result === 'object') return result; @@ -57,6 +63,9 @@ export = (ctx: Hexo) => { cache.hash = hash; cache.modified = mtime; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + // waiting warehouse v5.0.2 return cache.save().thenReturn({ type: 'update' }); diff --git a/lib/models/category.ts b/lib/models/category.ts index 2fdbfb58df..1a8049d485 100644 --- a/lib/models/category.ts +++ b/lib/models/category.ts @@ -1,6 +1,7 @@ import warehouse from 'warehouse'; import { slugize, full_url_for } from 'hexo-util'; import type Hexo from '../hexo'; +import type { CategorySchema } from '../types'; export = (ctx: Hexo) => { const Category = new warehouse.Schema({ @@ -8,7 +9,7 @@ export = (ctx: Hexo) => { parent: { type: warehouse.Schema.Types.CUID, ref: 'Category'} }); - Category.virtual('slug').get(function() { + Category.virtual('slug').get(function(this: CategorySchema) { let name = this.name; if (!name) return; @@ -28,7 +29,7 @@ export = (ctx: Hexo) => { return str; }); - Category.virtual('path').get(function() { + Category.virtual('path').get(function(this: CategorySchema) { let catDir = ctx.config.category_dir; if (catDir === '/') catDir = ''; if (!catDir.endsWith('/')) catDir += '/'; @@ -36,11 +37,11 @@ export = (ctx: Hexo) => { return `${catDir + this.slug}/`; }); - Category.virtual('permalink').get(function() { + Category.virtual('permalink').get(function(this: CategorySchema) { return full_url_for.call(ctx, this.path); }); - Category.virtual('posts').get(function() { + Category.virtual('posts').get(function(this: CategorySchema) { const PostCategory = ctx.model('PostCategory'); const ids = PostCategory.find({category_id: this._id}).map(item => item.post_id); @@ -50,14 +51,14 @@ export = (ctx: Hexo) => { }); }); - Category.virtual('length').get(function() { + Category.virtual('length').get(function(this: CategorySchema) { const PostCategory = ctx.model('PostCategory'); return PostCategory.find({category_id: this._id}).length; }); // Check whether a category exists - Category.pre('save', data => { + Category.pre('save', (data: CategorySchema) => { const { name, parent } = data; if (!name) return; @@ -73,7 +74,7 @@ export = (ctx: Hexo) => { }); // Remove PostCategory references - Category.pre('remove', data => { + Category.pre('remove', (data: CategorySchema) => { const PostCategory = ctx.model('PostCategory'); return PostCategory.remove({category_id: data._id}); }); diff --git a/lib/models/page.ts b/lib/models/page.ts index f1a96922d7..b3ee6f6d07 100644 --- a/lib/models/page.ts +++ b/lib/models/page.ts @@ -4,6 +4,7 @@ import Moment from './types/moment'; import moment from 'moment'; import { full_url_for } from 'hexo-util'; import type Hexo from '../hexo'; +import type { PageSchema } from '../types'; export = (ctx: Hexo) => { const Page = new warehouse.Schema({ @@ -30,11 +31,11 @@ export = (ctx: Hexo) => { more: {type: String} }); - Page.virtual('permalink').get(function() { + Page.virtual('permalink').get(function(this: PageSchema) { return full_url_for.call(ctx, this.path); }); - Page.virtual('full_source').get(function() { + Page.virtual('full_source').get(function(this: PageSchema) { return join(ctx.source_dir, this.source || ''); }); diff --git a/lib/models/post.ts b/lib/models/post.ts index 208e8ea477..31c2aeccf8 100644 --- a/lib/models/post.ts +++ b/lib/models/post.ts @@ -5,12 +5,13 @@ import Promise from 'bluebird'; import Moment from './types/moment'; import { full_url_for, Cache } from 'hexo-util'; import type Hexo from '../hexo'; +import type { CategorySchema, PostCategorySchema, PostSchema } from '../types'; -function pickID(data) { +function pickID(data: PostSchema | PostCategorySchema) { return data._id; } -function removeEmptyTag(tags) { +function removeEmptyTag(tags: string[]) { return tags.filter(tag => tag != null && tag !== '').map(tag => `${tag}`); } @@ -44,25 +45,25 @@ export = (ctx: Hexo) => { more: {type: String} }); - Post.virtual('path').get(function() { + Post.virtual('path').get(function(this: PostSchema) { const path = ctx.execFilterSync('post_permalink', this, {context: ctx}); return typeof path === 'string' ? path : ''; }); - Post.virtual('permalink').get(function() { + Post.virtual('permalink').get(function(this: PostSchema) { return full_url_for.call(ctx, this.path); }); - Post.virtual('full_source').get(function() { + Post.virtual('full_source').get(function(this: PostSchema) { return join(ctx.source_dir, this.source || ''); }); - Post.virtual('asset_dir').get(function() { + Post.virtual('asset_dir').get(function(this: PostSchema) { const src = this.full_source; return src.substring(0, src.length - extname(src).length) + sep; }); - Post.virtual('tags').get(function() { + Post.virtual('tags').get(function(this: PostSchema) { return tagsGetterCache.apply(this._id, () => { const PostTag = ctx.model('PostTag'); const Tag = ctx.model('Tag'); @@ -73,12 +74,12 @@ export = (ctx: Hexo) => { }); }); - Post.method('notPublished', function() { + Post.method('notPublished', function(this: PostSchema) { // The same condition as ctx._bindLocals - return (!ctx.config.future && this.date > Date.now()) || (!ctx._showDrafts() && this.published === false); + return (!ctx.config.future && this.date.valueOf() > Date.now()) || (!ctx._showDrafts() && this.published === false); }); - Post.method('setTags', function(tags) { + Post.method('setTags', function(this: PostSchema, tags: string[]) { if (this.notPublished()) { // Ignore tags of draft posts // If the post is unpublished then the tag needs to be removed, thus the function cannot be returned early here @@ -122,7 +123,7 @@ export = (ctx: Hexo) => { }).map(tag => PostTag.removeById(tag)); }); - Post.virtual('categories').get(function() { + Post.virtual('categories').get(function(this: PostSchema) { const PostCategory = ctx.model('PostCategory'); const Category = ctx.model('Category'); @@ -131,7 +132,7 @@ export = (ctx: Hexo) => { return Category.find({_id: {$in: ids}}); }); - Post.method('setCategories', function(cats: string[]) { + Post.method('setCategories', function(this: PostSchema, cats: (string | string[])[]) { if (this.notPublished()) { cats = []; } @@ -145,7 +146,7 @@ export = (ctx: Hexo) => { const PostCategory = ctx.model('PostCategory'); const Category = ctx.model('Category'); const id = this._id; - const allIds = []; + const allIds: string[] = []; const existed = PostCategory.find({post_id: id}, {lean: true}).map(pickID); const hasHierarchy = cats.filter(Array.isArray).length > 0; @@ -157,7 +158,7 @@ export = (ctx: Hexo) => { // MUST USE "Promise.each". return Promise.each(catHierarchy, (cat, i) => { // Find the category by name - const data = Category.findOne({ + const data: CategorySchema = Category.findOne({ name: cat, parent: i ? parentIds[i - 1] : {$exists: false} }, {lean: true}); @@ -174,14 +175,14 @@ export = (ctx: Hexo) => { return Category.insert(obj).catch(err => { // Try to find the category again. Throw the error if not found - const data = Category.findOne({ + const data: CategorySchema = Category.findOne({ name: cat, parent: i ? parentIds[i - 1] : {$exists: false} }, {lean: true}); if (data) return data; throw err; - }).then(data => { + }).then((data: CategorySchema) => { allIds.push(data._id); parentIds.push(data._id); return data; @@ -189,10 +190,10 @@ export = (ctx: Hexo) => { }); }; - return (hasHierarchy ? Promise.each(cats, addHierarchy) : Promise.resolve(addHierarchy(cats)) + return (hasHierarchy ? Promise.each(cats, addHierarchy) : Promise.resolve(addHierarchy(cats as string[])) ).then(() => allIds).map(catId => { // Find the reference - const ref = PostCategory.findOne({post_id: id, category_id: catId}, {lean: true}); + const ref: PostCategorySchema = PostCategory.findOne({post_id: id, category_id: catId}, {lean: true}); if (ref) return ref; // Insert the reference if not exist @@ -200,24 +201,24 @@ export = (ctx: Hexo) => { post_id: id, category_id: catId }); - }).then(postCats => // Remove old categories + }).then((postCats: PostCategorySchema[]) => // Remove old categories existed.filter(item => !postCats.map(pickID).includes(item))).map(cat => PostCategory.removeById(cat)); }); // Remove PostTag references - Post.pre('remove', data => { + Post.pre('remove', (data: PostSchema) => { const PostTag = ctx.model('PostTag'); return PostTag.remove({post_id: data._id}); }); // Remove PostCategory references - Post.pre('remove', data => { + Post.pre('remove', (data: PostSchema) => { const PostCategory = ctx.model('PostCategory'); return PostCategory.remove({post_id: data._id}); }); // Remove assets - Post.pre('remove', data => { + Post.pre('remove', (data: PostSchema) => { const PostAsset = ctx.model('PostAsset'); return PostAsset.remove({post: data._id}); }); diff --git a/lib/models/post_asset.ts b/lib/models/post_asset.ts index 8572029b8c..07c8ceebbe 100644 --- a/lib/models/post_asset.ts +++ b/lib/models/post_asset.ts @@ -1,6 +1,7 @@ import warehouse from 'warehouse'; import { join, posix } from 'path'; import type Hexo from '../hexo'; +import type { PostAssetSchema } from '../types'; export = (ctx: Hexo) => { const PostAsset = new warehouse.Schema({ @@ -11,7 +12,7 @@ export = (ctx: Hexo) => { renderable: {type: Boolean, default: true} }); - PostAsset.virtual('path').get(function() { + PostAsset.virtual('path').get(function(this: PostAssetSchema) { const Post = ctx.model('Post'); const post = Post.findById(this.post); if (!post) return; @@ -23,7 +24,7 @@ export = (ctx: Hexo) => { return posix.join(post.path.replace(/\.html?$/, ''), this.slug); }); - PostAsset.virtual('source').get(function() { + PostAsset.virtual('source').get(function(this: PostAssetSchema) { return join(ctx.base_dir, this._id); }); diff --git a/lib/models/tag.ts b/lib/models/tag.ts index 84a118aa25..b203f027c1 100644 --- a/lib/models/tag.ts +++ b/lib/models/tag.ts @@ -2,13 +2,14 @@ import warehouse from 'warehouse'; import { slugize, full_url_for } from 'hexo-util'; const { hasOwnProperty: hasOwn } = Object.prototype; import type Hexo from '../hexo'; +import type { TagSchema } from '../types'; export = (ctx: Hexo) => { const Tag = new warehouse.Schema({ name: {type: String, required: true} }); - Tag.virtual('slug').get(function() { + Tag.virtual('slug').get(function(this: TagSchema) { const map = ctx.config.tag_map || {}; let name = this.name; if (!name) return; @@ -20,18 +21,18 @@ export = (ctx: Hexo) => { return slugize(name, {transform: ctx.config.filename_case}); }); - Tag.virtual('path').get(function() { + Tag.virtual('path').get(function(this: TagSchema) { let tagDir = ctx.config.tag_dir; if (!tagDir.endsWith('/')) tagDir += '/'; return `${tagDir + this.slug}/`; }); - Tag.virtual('permalink').get(function() { + Tag.virtual('permalink').get(function(this: TagSchema) { return full_url_for.call(ctx, this.path); }); - Tag.virtual('posts').get(function() { + Tag.virtual('posts').get(function(this: TagSchema) { const PostTag = ctx.model('PostTag'); const ids = PostTag.find({tag_id: this._id}).map(item => item.post_id); @@ -41,7 +42,7 @@ export = (ctx: Hexo) => { }); }); - Tag.virtual('length').get(function() { + Tag.virtual('length').get(function(this: TagSchema) { // Note: this.posts.length is also working // But it's slow because `find` has to iterate over all posts const PostTag = ctx.model('PostTag'); @@ -50,7 +51,7 @@ export = (ctx: Hexo) => { }); // Check whether a tag exists - Tag.pre('save', data => { + Tag.pre('save', (data: TagSchema) => { const { name } = data; if (!name) return; @@ -63,7 +64,7 @@ export = (ctx: Hexo) => { }); // Remove PostTag references - Tag.pre('remove', data => { + Tag.pre('remove', (data: TagSchema) => { const PostTag = ctx.model('PostTag'); return PostTag.remove({tag_id: data._id}); }); diff --git a/lib/plugins/filter/new_post_path.ts b/lib/plugins/filter/new_post_path.ts index b25a1f9d2c..39de6dc5b2 100644 --- a/lib/plugins/filter/new_post_path.ts +++ b/lib/plugins/filter/new_post_path.ts @@ -18,7 +18,7 @@ const reservedKeys = { hash: true }; -function newPostPathFilter(this: Hexo, data: PostSchema = {}, replace?: boolean): Promise { +function newPostPathFilter(this: Hexo, data: Partial = {}, replace?: boolean): Promise { const sourceDir = this.source_dir; const draftDir = join(sourceDir, '_drafts'); const postDir = join(sourceDir, '_posts'); diff --git a/lib/plugins/processor/post.ts b/lib/plugins/processor/post.ts index 2baee39021..f38636b13d 100644 --- a/lib/plugins/processor/post.ts +++ b/lib/plugins/processor/post.ts @@ -9,6 +9,7 @@ import type { _File } from '../../box'; import type Hexo from '../../hexo'; import type { Stats } from 'fs'; import { PostSchema } from '../../types'; +import type Document from 'warehouse/dist/document'; const postDir = '_posts/'; const draftDir = '_drafts/'; @@ -278,7 +279,7 @@ function processAsset(ctx: Hexo, file: _File) { return; } - const savePostAsset = (post: PostSchema) => { + const savePostAsset = (post: Document) => { return PostAsset.save({ _id: id, slug: file.source.substring(post.asset_dir.length), diff --git a/lib/types.ts b/lib/types.ts index 4ca98f4e16..e454ab95b1 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -30,7 +30,8 @@ import type search_form from './plugins/helper/search_form'; import type tag_cloud from './plugins/helper/tagcloud'; import type toc from './plugins/helper/toc'; import type url_for from './plugins/helper/url_for'; -import Model from 'warehouse/dist/model'; +import type Model from 'warehouse/dist/model'; +import type Document from 'warehouse/dist/document'; export type NodeJSLikeCallback = (err: E, result?: R) => void @@ -47,30 +48,75 @@ export interface RenderData { } // Schema +export interface TagSchema { + id?: string; + _id?: string; + name: string; + slug: string; + path: string; + permalink: string; + posts: any; + length: number; +} + +export interface CategorySchema { + id?: string; + _id?: string; + name: string; + parent?: string; + slug: string; + path: string; + permalink: string; + posts: any; + length: number; +} + +export interface PostCategorySchema { + _id?: string; + post_id: string; + category_id: string; +} + +export interface PostTagSchema { + _id?: string; + post_id: string; + tag_id: string; +} + +export interface PostAssetSchema { + _id: string; + slug: string; + modified: boolean; + post: string; + renderable: boolean; + path: string; + source: string; +} + export interface PostSchema { - id?: string | number; - _id?: string | number; - title?: string; - date?: moment.Moment, - updated?: moment.Moment, - comments?: boolean; - layout?: string; - _content?: string; - source?: string; - slug?: string; + id?: string; + _id?: string; + title: string; + date: moment.Moment, + updated: moment.Moment, + comments: boolean; + layout: string; + _content: string; + source: string; + slug: string; photos?: string[]; - raw?: string; - published?: boolean; + raw: string; + published: boolean; content?: string; excerpt?: string; more?: string; author?: string; - asset_dir?: string; - full_source?: string; - path?: string; - permalink?: string; - categories?: any; - tags?: any; + asset_dir: string; + full_source: string; + path: string; + permalink: string; + categories: Query; + tags?: Query; __permalink?: string; __post?: boolean; canonical_path?: string; @@ -83,25 +129,28 @@ export interface PostSchema { total?: number; description?: string; [key: string]: any; + notPublished: () => boolean; + setTags: (tags: string[]) => any; + setCategories: (cats: (string | string[])[]) => any; } export interface PageSchema { - _id?: string | number; - title?: string; - date?: moment.Moment, - updated?: moment.Moment, - comments?: boolean; - layout?: string; - _content?: string; - source?: string; - path?: string; - raw?: string; + _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; + full_source: string; + permalink: string; author?: string; - full_source?: string; - permalink?: string; tags?: any; canonical_path?: string; lang?: string; @@ -114,24 +163,6 @@ export interface PageSchema { description?: string; } -export interface CategorySchema { - id?: string | number; - _id?: string | number; - name?: string; - parent?: string | number; - slug?: string; - path?: string; - permalink?: string; - posts?: any; - length?: number; -} - -export interface TagSchema { - id?: string | number; - _id?: string | number; - name?: string; -} - export interface AssetSchema { _id?: string; path: string; @@ -140,6 +171,12 @@ export interface AssetSchema { source: string; } +export interface CacheSchema { + _id: string; + hash: string; + modified: number; +} + export interface LocalsType { page: PostSchema | PageSchema; path: string; @@ -225,7 +262,7 @@ export type SimplePostGenerator = { export type NormalPostGenerator = { path: string; layout: string[]; - data: PostSchema; + data: PostSchema | Document; } export type PostGenerator = SimplePostGenerator | NormalPostGenerator; diff --git a/package.json b/package.json index c5cde29e52..a636795964 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,9 @@ "@types/abbrev": "^1.1.3", "@types/bluebird": "^3.5.37", "@types/chai": "^4.3.11", + "@types/graceful-fs": "^4.1.9", "@types/js-yaml": "^4.0.9", + "@types/micromatch": "^4.0.7", "@types/mocha": "^10.0.6", "@types/node": "^18.11.8 <18.19.9", "@types/nunjucks": "^3.2.2", From 5d0ae1324da72dfce5e3d5197e4bbe664e67dc4f Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Tue, 30 Apr 2024 16:31:43 +0800 Subject: [PATCH 02/10] refator: refactor types --- lib/plugins/console/list/category.ts | 6 ++++-- lib/plugins/console/list/page.ts | 6 ++++-- lib/plugins/console/list/post.ts | 6 ++++-- lib/plugins/console/list/route.ts | 8 ++++---- lib/plugins/console/list/tag.ts | 6 ++++-- test/scripts/hexo/hexo.ts | 2 ++ 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/lib/plugins/console/list/category.ts b/lib/plugins/console/list/category.ts index a1c6527c80..e9424a3588 100644 --- a/lib/plugins/console/list/category.ts +++ b/lib/plugins/console/list/category.ts @@ -2,11 +2,13 @@ import { underline } from 'picocolors'; import table from 'text-table'; import { stringLength } from './common'; import type Hexo from '../../../hexo'; +import type { CategorySchema } from '../../../types'; +import type Model from 'warehouse/dist/model'; function listCategory(this: Hexo): void { - const categories = this.model('Category'); + const categories: Model = this.model('Category'); - const data = categories.sort({name: 1}).map(cate => [cate.name, String(cate.length)]); + const data = categories.sort({name: 1}).map((cate: CategorySchema) => [cate.name, String(cate.length)]); // Table header const header = ['Name', 'Posts'].map(str => underline(str)); diff --git a/lib/plugins/console/list/page.ts b/lib/plugins/console/list/page.ts index 8b9de1bc09..e3a371e8d4 100644 --- a/lib/plugins/console/list/page.ts +++ b/lib/plugins/console/list/page.ts @@ -2,11 +2,13 @@ import { magenta, underline, gray } from 'picocolors'; import table from 'text-table'; import { stringLength } from './common'; import type Hexo from '../../../hexo'; +import type { PageSchema } from '../../../types'; +import type Model from 'warehouse/dist/model'; function listPage(this: Hexo): void { - const Page = this.model('Page'); + const Page: Model = this.model('Page'); - const data = Page.sort({date: 1}).map(page => { + const data = Page.sort({date: 1}).map((page: PageSchema) => { const date = page.date.format('YYYY-MM-DD'); return [gray(date), page.title, magenta(page.source)]; }); diff --git a/lib/plugins/console/list/post.ts b/lib/plugins/console/list/post.ts index 280b339df8..e213b7577d 100644 --- a/lib/plugins/console/list/post.ts +++ b/lib/plugins/console/list/post.ts @@ -2,15 +2,17 @@ import { gray, magenta, underline } from 'picocolors'; import table from 'text-table'; import { stringLength } from './common'; import type Hexo from '../../../hexo'; +import type { PostSchema } from '../../../types'; +import type Model from 'warehouse/dist/model'; function mapName(item) { return item.name; } function listPost(this: Hexo): void { - const Post = this.model('Post'); + const Post: Model = this.model('Post'); - const data = Post.sort({published: -1, date: 1}).map(post => { + const data = Post.sort({published: -1, date: 1}).map((post: PostSchema) => { const date = post.published ? post.date.format('YYYY-MM-DD') : 'Draft'; const tags = post.tags.map(mapName); const categories = post.categories.map(mapName); diff --git a/lib/plugins/console/list/route.ts b/lib/plugins/console/list/route.ts index 2c15e217cc..3e2c1f8a85 100644 --- a/lib/plugins/console/list/route.ts +++ b/lib/plugins/console/list/route.ts @@ -14,9 +14,9 @@ function listRoute(this: Hexo): void { console.log(s); } -function buildTree(routes) { - const obj = {}; - let cursor; +function buildTree(routes: string[]) { + const obj: Record = {}; + let cursor: typeof obj; for (let i = 0, len = routes.length; i < len; i++) { const item = routes[i].split('/'); @@ -32,7 +32,7 @@ function buildTree(routes) { return obj; } -function buildNodes(tree) { +function buildNodes(tree: Record) { const nodes = []; for (const [key, item] of Object.entries(tree)) { diff --git a/lib/plugins/console/list/tag.ts b/lib/plugins/console/list/tag.ts index 4ce37595d1..b34d7ad6c3 100644 --- a/lib/plugins/console/list/tag.ts +++ b/lib/plugins/console/list/tag.ts @@ -2,11 +2,13 @@ import { magenta, underline } from 'picocolors'; import table from 'text-table'; import { stringLength } from './common'; import type Hexo from '../../../hexo'; +import type { TagSchema } from '../../../types'; +import type Model from 'warehouse/dist/model'; function listTag(this: Hexo): void { - const Tag = this.model('Tag'); + const Tag: Model = this.model('Tag'); - const data = Tag.sort({name: 1}).map(tag => [tag.name, String(tag.length), magenta(tag.path)]); + const data = Tag.sort({name: 1}).map((tag: TagSchema) => [tag.name, String(tag.length), magenta(tag.path)]); // Table header const header = ['Name', 'Posts', 'Path'].map(str => underline(str)); diff --git a/test/scripts/hexo/hexo.ts b/test/scripts/hexo/hexo.ts index 9dfae90aaf..efbc72b9a6 100644 --- a/test/scripts/hexo/hexo.ts +++ b/test/scripts/hexo/hexo.ts @@ -168,6 +168,7 @@ describe('Hexo', () => { themeConfig.a.b.should.eql(3); const Locals = hexo._generateLocals(); + // @ts-expect-error const { theme: themeLocals } = new Locals('', {path: '', layout: [], data: {}}); themeLocals.a.should.have.own.property('c'); @@ -187,6 +188,7 @@ describe('Hexo', () => { themeConfig.c.should.eql(3); const Locals = hexo._generateLocals(); + // @ts-expect-error const { theme: themeLocals } = new Locals('', {path: '', layout: [], data: {}}); themeLocals.should.have.own.property('c'); From 2ebf78ac6bd64bf2ee53f8caf87973031df4f381 Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Tue, 30 Apr 2024 17:34:06 +0800 Subject: [PATCH 03/10] fix: ts-expect-error --- lib/hexo/default_config.ts | 6 +- lib/hexo/index.ts | 2 +- lib/models/cache.ts | 2 +- test/scripts/box/box.ts | 55 +++++++------- test/scripts/console/config.ts | 3 +- test/scripts/console/deploy.ts | 3 +- test/scripts/console/generate.ts | 43 ++++++----- test/scripts/console/list.ts | 5 +- test/scripts/console/list_categories.ts | 5 +- test/scripts/console/list_post.ts | 5 +- test/scripts/console/list_tags.ts | 5 +- test/scripts/console/new.ts | 23 +++--- test/scripts/console/publish.ts | 5 +- test/scripts/console/render.ts | 13 ++-- test/scripts/extend/console.ts | 12 +-- test/scripts/extend/deployer.ts | 4 +- test/scripts/extend/filter.ts | 6 +- test/scripts/extend/generator.ts | 2 +- test/scripts/extend/helper.ts | 4 +- test/scripts/extend/injector.ts | 4 +- test/scripts/extend/migrator.ts | 4 +- test/scripts/extend/processor.ts | 4 +- test/scripts/extend/renderer.ts | 25 +++---- test/scripts/extend/tag.ts | 6 +- test/scripts/filters/backtick_code_block.ts | 6 +- test/scripts/filters/external_link.ts | 2 +- test/scripts/filters/save_database.ts | 5 +- test/scripts/generators/page.ts | 5 +- test/scripts/generators/post.ts | 7 +- test/scripts/helpers/date.ts | 12 +-- test/scripts/helpers/feed_tag.ts | 4 +- test/scripts/helpers/partial.ts | 7 +- test/scripts/helpers/search_form.ts | 2 +- test/scripts/helpers/tagcloud.ts | 7 +- test/scripts/hexo/hexo.ts | 15 ++-- test/scripts/hexo/load_plugins.ts | 21 +++--- test/scripts/hexo/locals.ts | 8 +- test/scripts/hexo/render.ts | 6 +- test/scripts/hexo/router.ts | 19 +++-- test/scripts/hexo/validate_config.ts | 10 +-- test/scripts/models/moment.ts | 4 +- test/scripts/models/post.ts | 11 ++- test/scripts/processors/common.ts | 10 +-- test/scripts/processors/data.ts | 7 +- test/scripts/processors/post.ts | 83 ++++++++++----------- test/scripts/tags/asset_img.ts | 5 +- test/scripts/tags/asset_link.ts | 5 +- test/scripts/tags/asset_path.ts | 5 +- test/scripts/tags/include_code.ts | 5 +- test/scripts/theme_processors/config.ts | 7 +- test/scripts/theme_processors/i18n.ts | 7 +- test/scripts/theme_processors/source.ts | 15 ++-- test/scripts/theme_processors/view.ts | 7 +- 53 files changed, 258 insertions(+), 295 deletions(-) diff --git a/lib/hexo/default_config.ts b/lib/hexo/default_config.ts index 6d1ede870c..89a10f77f3 100644 --- a/lib/hexo/default_config.ts +++ b/lib/hexo/default_config.ts @@ -23,7 +23,7 @@ export = { category_dir: 'categories', code_dir: 'downloads/code', i18n_dir: ':lang', - skip_render: [], + skip_render: [] as string[], // Writing new_post_name: ':title.md', default_layout: 'post', @@ -44,7 +44,7 @@ export = { line_number: true, tab_replace: '', wrap: true, - exclude_languages: [], + exclude_languages: [] as string[], language_attr: false, hljs: false, line_threshold: 0, @@ -55,7 +55,7 @@ export = { preprocess: true, line_number: true, tab_replace: '', - exclude_languages: [], + exclude_languages: [] as string[], strip_indent: true }, // Category & Tag diff --git a/lib/hexo/index.ts b/lib/hexo/index.ts index b9ca764dd4..255d801ce6 100644 --- a/lib/hexo/index.ts +++ b/lib/hexo/index.ts @@ -622,7 +622,7 @@ class Hexo extends EventEmitter { // add Route const path = route.format(generatorResult.path); // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore + // @ts-expect-error const { data, layout } = generatorResult; if (!layout) { diff --git a/lib/models/cache.ts b/lib/models/cache.ts index 6d88dc17ab..4189829ec2 100644 --- a/lib/models/cache.ts +++ b/lib/models/cache.ts @@ -64,7 +64,7 @@ export = (ctx: Hexo) => { cache.modified = mtime; // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore + // @ts-expect-error // waiting warehouse v5.0.2 return cache.save().thenReturn({ type: 'update' diff --git a/test/scripts/box/box.ts b/test/scripts/box/box.ts index 55331677f2..5528b9464e 100644 --- a/test/scripts/box/box.ts +++ b/test/scripts/box/box.ts @@ -2,8 +2,7 @@ import { join, sep } from 'path'; import { appendFile, mkdir, mkdirs, rename, rmdir, stat, unlink, writeFile } from 'hexo-fs'; import { hash, Pattern } from 'hexo-util'; import { spy, match, assert as sinonAssert } from 'sinon'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import Box from '../../../lib/box'; import chai from 'chai'; @@ -65,7 +64,7 @@ describe('Box', () => { it('addProcessor() - no fn', () => { const box = newBox(); - // @ts-ignore + // @ts-expect-error should.throw(() => box.addProcessor('test'), 'fn must be a function'); }); @@ -77,7 +76,7 @@ describe('Box', () => { data[file.path] = file; }); - await Promise.all([ + await BluebirdPromise.all([ writeFile(join(box.base, 'a.txt'), 'a'), writeFile(join(box.base, 'b', 'c.js'), 'c') ]); @@ -125,7 +124,7 @@ describe('Box', () => { const processor = spy(); box.addProcessor(processor); - await Promise.all([ + await BluebirdPromise.all([ writeFile(path, 'a'), box.Cache.insert({ _id: cacheId, @@ -217,7 +216,7 @@ describe('Box', () => { const processor = spy(); box.addProcessor(processor); - await Promise.all([ + await BluebirdPromise.all([ mkdirs(box.base), box.Cache.insert({ _id: cacheId @@ -282,7 +281,7 @@ describe('Box', () => { data[file.path] = file; }); - await Promise.all([ + await BluebirdPromise.all([ writeFile(join(box.base, 'foo.txt'), 'foo'), writeFile(join(box.base, 'ignore_me', 'bar.txt'), 'ignore_me') ]); @@ -301,7 +300,7 @@ describe('Box', () => { data[file.path] = file; }); - await Promise.all([ + await BluebirdPromise.all([ writeFile(join(box.base, 'foo.txt'), 'foo'), writeFile(join(box.base, 'ignore_me', 'bar.txt'), 'ignore_me'), writeFile(join(box.base, 'ignore_me_too.txt'), 'ignore_me_too') @@ -324,7 +323,7 @@ describe('Box', () => { await writeFile(src, 'a'); await box.watch(); box.isWatching().should.be.true; - await Promise.delay(500); + await BluebirdPromise.delay(500); sinonAssert.calledWithMatch(processor.firstCall, { source: src, @@ -347,13 +346,13 @@ describe('Box', () => { box.addProcessor(processor); - await Promise.all([ + await BluebirdPromise.all([ writeFile(src, 'a'), Cache.insert({_id: cacheId}) ]); await box.watch(); await appendFile(src, 'b'); - await Promise.delay(500); + await BluebirdPromise.delay(500); sinonAssert.calledWithMatch(processor.lastCall, { source: src, @@ -376,13 +375,13 @@ describe('Box', () => { box.addProcessor(processor); - await Promise.all([ + await BluebirdPromise.all([ writeFile(src, 'a'), Cache.insert({_id: cacheId}) ]); await box.watch(); await unlink(src); - await Promise.delay(500); + await BluebirdPromise.delay(500); sinonAssert.calledWithMatch(processor.lastCall, { source: src, @@ -407,13 +406,13 @@ describe('Box', () => { box.addProcessor(processor); - await Promise.all([ + await BluebirdPromise.all([ writeFile(src, 'a'), Cache.insert({_id: cacheId}) ]); await box.watch(); await rename(src, newSrc); - await Promise.delay(500); + await BluebirdPromise.delay(500); for (const [file] of processor.args.slice(-2)) { switch (file.type) { @@ -445,13 +444,13 @@ describe('Box', () => { box.addProcessor(processor); - await Promise.all([ + await BluebirdPromise.all([ writeFile(src, 'a'), Cache.insert({_id: cacheId}) ]); await box.watch(); await rename(join(box.base, 'a'), join(box.base, 'b')); - await Promise.delay(500); + await BluebirdPromise.delay(500); for (const [file] of processor.args.slice(-2)) { switch (file.type) { @@ -484,17 +483,17 @@ describe('Box', () => { box.addProcessor(processor); - await Promise.all([ + await BluebirdPromise.all([ writeFile(src1, 'a'), Cache.insert({_id: cacheId1}) ]); - await Promise.all([ + await BluebirdPromise.all([ writeFile(src2, 'b'), Cache.insert({_id: cacheId2}) ]); await box.watch(); await appendFile(src1, 'aaa'); - await Promise.delay(500); + await BluebirdPromise.delay(500); const file = processor.lastCall.args[0]; @@ -506,7 +505,7 @@ describe('Box', () => { }); await appendFile(src2, 'bbb'); - await Promise.delay(500); + await BluebirdPromise.delay(500); const file2 = processor.lastCall.args[0]; file2.should.eql(file); // not changed @@ -531,21 +530,21 @@ describe('Box', () => { box.addProcessor(processor); - await Promise.all([ + await BluebirdPromise.all([ writeFile(src1, 'a'), Cache.insert({_id: cacheId1}) ]); - await Promise.all([ + await BluebirdPromise.all([ writeFile(src2, 'b'), Cache.insert({_id: cacheId2}) ]); - await Promise.all([ + await BluebirdPromise.all([ writeFile(src3, 'c'), Cache.insert({_id: cacheId3}) ]); await box.watch(); await appendFile(src1, 'aaa'); - await Promise.delay(500); + await BluebirdPromise.delay(500); const file = processor.lastCall.args[0]; @@ -557,12 +556,12 @@ describe('Box', () => { }); await appendFile(src2, 'bbb'); - await Promise.delay(500); + await BluebirdPromise.delay(500); processor.lastCall.args[0].should.eql(file); // not changed await appendFile(src3, 'ccc'); - await Promise.delay(500); + await BluebirdPromise.delay(500); processor.lastCall.args[0].should.eql(file); // not changed @@ -592,7 +591,7 @@ describe('Box', () => { data.push(file.path); }); - await Promise.all([ + await BluebirdPromise.all([ writeFile(join(box.base, 'a.txt'), 'a'), writeFile(join(box.base, 'b', 'c.js'), 'c') ]); diff --git a/test/scripts/console/config.ts b/test/scripts/console/config.ts index 0a70da3c73..8dc26b75ca 100644 --- a/test/scripts/console/config.ts +++ b/test/scripts/console/config.ts @@ -57,8 +57,7 @@ describe('config', () => { await config({_: ['server.port']}); sinonAssert.calledWith(logStub, (hexo.config as any).server.port); } finally { - // @ts-ignore - delete hexo.config.server; + delete(hexo.config as any).server; logStub.restore(); } }); diff --git a/test/scripts/console/deploy.ts b/test/scripts/console/deploy.ts index efcb98f5d4..fb8f291d45 100644 --- a/test/scripts/console/deploy.ts +++ b/test/scripts/console/deploy.ts @@ -25,8 +25,7 @@ describe('deploy', () => { after(() => rmdir(hexo.base_dir)); it('no deploy config', () => { - // @ts-ignore - delete hexo.config.deploy; + delete(hexo.config as any).deploy; const logStub = stub(console, 'log'); diff --git a/test/scripts/console/generate.ts b/test/scripts/console/generate.ts index bf6a04615e..0ab3e6c191 100644 --- a/test/scripts/console/generate.ts +++ b/test/scripts/console/generate.ts @@ -1,7 +1,6 @@ import { join } from 'path'; import { emptyDir, exists, mkdirs, readFile, rmdir, stat, unlink, writeFile } from 'hexo-fs'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import { spy } from 'sinon'; import chai from 'chai'; const should = chai.should(); @@ -30,7 +29,7 @@ describe('generate', () => { }); const testGenerate = async (options?: any) => { - await Promise.all([ + await BluebirdPromise.all([ // Add some source files writeFile(join(hexo.source_dir, 'test.txt'), 'test'), writeFile(join(hexo.source_dir, 'faz', 'yo.txt'), 'yoooo'), @@ -41,7 +40,7 @@ describe('generate', () => { ]); await generate(options); - const result = await Promise.all([ + const result = await BluebirdPromise.all([ readFile(join(hexo.public_dir, 'test.txt')), readFile(join(hexo.public_dir, 'faz', 'yo.txt')), exists(join(hexo.public_dir, 'foo.txt')), @@ -59,7 +58,7 @@ describe('generate', () => { it('default', () => testGenerate()); it('public_dir is not a directory', async () => { - await Promise.all([ + await BluebirdPromise.all([ // Add some source files writeFile(join(hexo.source_dir, 'test.txt'), 'test'), // Add some files to public folder @@ -97,7 +96,7 @@ describe('generate', () => { result.should.eql(content); // Remove source files and generated files - await Promise.all([ + await BluebirdPromise.all([ unlink(src), unlink(dest) ]); @@ -128,7 +127,7 @@ describe('generate', () => { result.should.eql(newContent); // Remove source files and generated files - await Promise.all([ + await BluebirdPromise.all([ unlink(src), unlink(dest) ]); @@ -148,7 +147,7 @@ describe('generate', () => { let stats = await stat(dest); const mtime = stats.mtime.getTime(); - await Promise.delay(1000); + await BluebirdPromise.delay(1000); // Force regenerate await generate({ force: true }); @@ -157,7 +156,7 @@ describe('generate', () => { stats.mtime.getTime().should.above(mtime); // Remove source files and generated files - await Promise.all([ + await BluebirdPromise.all([ unlink(src), unlink(dest) ]); @@ -173,7 +172,7 @@ describe('generate', () => { // Update the file await writeFile(src, content); - await Promise.delay(300); + await BluebirdPromise.delay(300); // Check the updated file const result = await readFile(dest); @@ -199,7 +198,7 @@ describe('generate', () => { it('update theme source files', async () => { // Add some source files - await Promise.all([ + await BluebirdPromise.all([ // Add some source files writeFile(join(hexo.theme_dir, 'source', 'a.txt'), 'a'), writeFile(join(hexo.theme_dir, 'source', 'b.txt'), 'b'), @@ -208,7 +207,7 @@ describe('generate', () => { await generate(); // Update source file - await Promise.all([ + await BluebirdPromise.all([ writeFile(join(hexo.theme_dir, 'source', 'b.txt'), 'bb'), writeFile(join(hexo.theme_dir, 'source', 'c.njk'), 'cc') ]); @@ -216,10 +215,10 @@ describe('generate', () => { // Generate again await generate(); - await Promise.delay(300); + await BluebirdPromise.delay(300); // Read the updated source file - const result = await Promise.all([ + const result = await BluebirdPromise.all([ readFile(join(hexo.public_dir, 'b.txt')), readFile(join(hexo.public_dir, 'c.html')) ]); @@ -229,7 +228,7 @@ describe('generate', () => { }); it('proceeds after error when bail option is not set', async () => { - hexo.extend.renderer.register('err', 'html', () => Promise.reject(new Error('Testing unhandled exception'))); + hexo.extend.renderer.register('err', 'html', () => BluebirdPromise.reject(new Error('Testing unhandled exception'))); hexo.extend.generator.register('test_page', () => [ { @@ -245,7 +244,7 @@ describe('generate', () => { }); it('proceeds after error when bail option is set to false', async () => { - hexo.extend.renderer.register('err', 'html', () => Promise.reject(new Error('Testing unhandled exception'))); + hexo.extend.renderer.register('err', 'html', () => BluebirdPromise.reject(new Error('Testing unhandled exception'))); hexo.extend.generator.register('test_page', () => [ { @@ -261,7 +260,7 @@ describe('generate', () => { }); it('breaks after error when bail option is set to true', async () => { - hexo.extend.renderer.register('err', 'html', () => Promise.reject(new Error('Testing unhandled exception'))); + hexo.extend.renderer.register('err', 'html', () => BluebirdPromise.reject(new Error('Testing unhandled exception'))); hexo.extend.generator.register('test_page', () => [ { @@ -295,7 +294,7 @@ describe('generate', () => { }, { path: 'resource-3', - data: () => Promise.resolve(Buffer.from('string')) + data: () => BluebirdPromise.resolve(Buffer.from('string')) } ] ); @@ -322,13 +321,13 @@ describe('generate - watch (delete)', () => { const exist = await exists(hexo.base_dir); if (exist) { await emptyDir(hexo.base_dir); - await Promise.delay(500); + await BluebirdPromise.delay(500); await rmdir(hexo.base_dir); } }); const testGenerate = async options => { - await Promise.all([ + await BluebirdPromise.all([ // Add some source files writeFile(join(hexo.source_dir, 'test.txt'), 'test'), writeFile(join(hexo.source_dir, 'faz', 'yo.txt'), 'yoooo'), @@ -339,7 +338,7 @@ describe('generate - watch (delete)', () => { ]); await generate(options); - const result = await Promise.all([ + const result = await BluebirdPromise.all([ readFile(join(hexo.public_dir, 'test.txt')), readFile(join(hexo.public_dir, 'faz', 'yo.txt')), exists(join(hexo.public_dir, 'foo.txt')), @@ -358,7 +357,7 @@ describe('generate - watch (delete)', () => { await testGenerate({ watch: true }); await unlink(join(hexo.source_dir, 'test.txt')); - await Promise.delay(500); + await BluebirdPromise.delay(500); const exist = await exists(join(hexo.public_dir, 'test.txt')); exist.should.be.false; diff --git a/test/scripts/console/list.ts b/test/scripts/console/list.ts index 0aa0b8ec24..d9353102f1 100644 --- a/test/scripts/console/list.ts +++ b/test/scripts/console/list.ts @@ -1,6 +1,5 @@ import { spy, stub, assert as sinonAssert, SinonSpy } from 'sinon'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import listConsole from '../../../lib/plugins/console/list'; type OriginalParams = Parameters; @@ -24,7 +23,7 @@ describe('Console list', () => { it('has args', async () => { const logStub = stub(console, 'log'); - hexo.load = () => Promise.resolve(); + hexo.load = () => BluebirdPromise.resolve(); const list: (...args: OriginalParams) => OriginalReturn = listConsole.bind(hexo); diff --git a/test/scripts/console/list_categories.ts b/test/scripts/console/list_categories.ts index 2a5d47fb76..6de2ae98b5 100644 --- a/test/scripts/console/list_categories.ts +++ b/test/scripts/console/list_categories.ts @@ -1,5 +1,4 @@ -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import { stub, assert as sinonAssert } from 'sinon'; import Hexo from '../../../lib/hexo'; import listCategory from '../../../lib/plugins/console/list/category'; @@ -36,7 +35,7 @@ describe('Console list', () => { await hexo.init(); const output = await Post.insert(posts); - await Promise.each([ + await BluebirdPromise.each([ ['foo'], ['baz'], ['baz'] diff --git a/test/scripts/console/list_post.ts b/test/scripts/console/list_post.ts index 72f92a44b1..7b47e170b1 100644 --- a/test/scripts/console/list_post.ts +++ b/test/scripts/console/list_post.ts @@ -1,5 +1,4 @@ -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import { stub, assert as sinonAssert } from 'sinon'; import Hexo from '../../../lib/hexo'; import listPost from '../../../lib/plugins/console/list/post'; @@ -45,7 +44,7 @@ describe('Console list', () => { await hexo.init(); const output = await Post.insert(posts); - await Promise.each(tags, (tags, i) => output[i].setTags(tags)); + await BluebirdPromise.each(tags, (tags, i) => output[i].setTags(tags)); await hexo.locals.invalidate(); listPosts(); diff --git a/test/scripts/console/list_tags.ts b/test/scripts/console/list_tags.ts index 4be2747913..248a2c0190 100644 --- a/test/scripts/console/list_tags.ts +++ b/test/scripts/console/list_tags.ts @@ -1,5 +1,4 @@ -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import { stub, assert as sinonAssert } from 'sinon'; import Hexo from '../../../lib/hexo'; import listTag from '../../../lib/plugins/console/list/tag'; @@ -39,7 +38,7 @@ describe('Console list', () => { await hexo.init(); const output = await Post.insert(posts); - await Promise.each([ + await BluebirdPromise.each([ ['foo'], ['baz'], ['baz'] diff --git a/test/scripts/console/new.ts b/test/scripts/console/new.ts index 29448ea909..421b1b43a7 100644 --- a/test/scripts/console/new.ts +++ b/test/scripts/console/new.ts @@ -1,8 +1,7 @@ import { exists, mkdirs, readFile, rmdir, unlink } from 'hexo-fs'; import moment from 'moment'; import { join } from 'path'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import { useFakeTimers, spy, SinonSpy } from 'sinon'; import Hexo from '../../../lib/hexo'; import newConsole from '../../../lib/plugins/console/new'; @@ -22,7 +21,7 @@ describe('new', () => { await mkdirs(hexo.base_dir); await hexo.init(); - await Promise.all([ + await BluebirdPromise.all([ hexo.scaffold.set('post', [ 'title: {{ title }}', 'date: {{ date }}', @@ -202,7 +201,7 @@ describe('new', () => { const exist = await exists(path); exist.should.be.true; - await Promise.all([ + await BluebirdPromise.all([ unlink(path), unlink(join(hexo.source_dir, '_posts', 'Hello-World.md')) ]); @@ -372,12 +371,12 @@ describe('new', () => { find_pkg_1: { default: (_cwd, _args) => { args = _args; - return Promise.resolve(); + return BluebirdPromise.resolve(); } } })(async () => { process.argv = ['hexo', 'new', '--path', '123', 'test']; - // @ts-ignore + // @ts-expect-error cli(null, null); args.path.should.eql('123'); process.argv = []; @@ -391,12 +390,12 @@ describe('new', () => { find_pkg_1: { default: (_cwd, _args) => { args = _args; - return Promise.resolve(); + return BluebirdPromise.resolve(); } } })(async () => { process.argv = ['hexo', 'new', '-p', '123', 'test']; - // @ts-ignore + // @ts-expect-error cli(null, null); args.p.should.eql('123'); process.argv = []; @@ -410,12 +409,12 @@ describe('new', () => { find_pkg_1: { default: (_cwd, _args) => { args = _args; - return Promise.resolve(); + return BluebirdPromise.resolve(); } } })(async () => { process.argv = ['hexo', 'new', '--slug', '123', 'test']; - // @ts-ignore + // @ts-expect-error cli(null, null); args.slug.should.eql('123'); process.argv = []; @@ -429,12 +428,12 @@ describe('new', () => { find_pkg_1: { default: (_cwd, _args) => { args = _args; - return Promise.resolve(); + return BluebirdPromise.resolve(); } } })(async () => { process.argv = ['hexo', 'new', '-s', '123', 'test']; - // @ts-ignore + // @ts-expect-error cli(null, null); args.s.should.eql('123'); process.argv = []; diff --git a/test/scripts/console/publish.ts b/test/scripts/console/publish.ts index afd2dcef7d..2cbb7aaf2f 100644 --- a/test/scripts/console/publish.ts +++ b/test/scripts/console/publish.ts @@ -1,8 +1,7 @@ import { exists, mkdirs, readFile, rmdir, unlink } from 'hexo-fs'; import moment from 'moment'; import { join } from 'path'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import { useFakeTimers, spy, SinonSpy, SinonFakeTimers } from 'sinon'; import Hexo from '../../../lib/hexo'; import publishConsole from '../../../lib/plugins/console/publish'; @@ -119,7 +118,7 @@ describe('publish', () => { const exist = await exists(path); exist.should.be.true; - await Promise.all([ + await BluebirdPromise.all([ unlink(path), unlink(join(hexo.source_dir, '_posts', 'Hello-World.md')) ]); diff --git a/test/scripts/console/render.ts b/test/scripts/console/render.ts index 784c5d397e..45d9f52e3a 100644 --- a/test/scripts/console/render.ts +++ b/test/scripts/console/render.ts @@ -1,7 +1,6 @@ import { mkdirs, readFile, rmdir, unlink, writeFile } from 'hexo-fs'; import { join } from 'path'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import { spy, SinonSpy } from 'sinon'; import Hexo from '../../../lib/hexo'; import renderConsole from '../../../lib/plugins/console/render'; @@ -51,7 +50,7 @@ describe('render', () => { } }); - await Promise.all([ + await BluebirdPromise.all([ unlink(src), unlink(dest) ]); @@ -72,7 +71,7 @@ describe('render', () => { } }); - await Promise.all([ + await BluebirdPromise.all([ unlink(src), unlink(dest) ]); @@ -93,7 +92,7 @@ describe('render', () => { } }); - await Promise.all([ + await BluebirdPromise.all([ unlink(src), unlink(dest) ]); @@ -116,7 +115,7 @@ describe('render', () => { } }); - await Promise.all([ + await BluebirdPromise.all([ unlink(src), unlink(dest) ]); @@ -137,7 +136,7 @@ describe('render', () => { } }, null, ' ')); - await Promise.all([ + await BluebirdPromise.all([ unlink(src), unlink(dest) ]); diff --git a/test/scripts/extend/console.ts b/test/scripts/extend/console.ts index ab70d3d04a..2633f18575 100644 --- a/test/scripts/extend/console.ts +++ b/test/scripts/extend/console.ts @@ -7,7 +7,7 @@ describe('Console', () => { const c = new Console(); // no name - // @ts-ignore + // @ts-expect-error should.throw(() => c.register(), TypeError, 'name is required'); // name, fn @@ -16,18 +16,18 @@ describe('Console', () => { c.get('test').should.exist; // name, not fn - // @ts-ignore + // @ts-expect-error should.throw(() => c.register('test'), TypeError, 'fn must be a function'); // name, desc, fn c.register('test', 'this is a test', () => {}); c.get('test').should.exist; - // @ts-ignore - c.get('test').desc.should.eql('this is a test'); + + c.get('test').desc!.should.eql('this is a test'); // name, desc, not fn - // @ts-ignore + // @ts-expect-error should.throw(() => c.register('test', 'this is a test'), TypeError, 'fn must be a function'); // name, options, fn @@ -44,7 +44,7 @@ describe('Console', () => { c.get('test').options!.init!.should.be.true; // name, desc, options, not fn - // @ts-ignore + // @ts-expect-error should.throw(() => c.register('test', 'this is a test', {init: true}), TypeError, 'fn must be a function'); }); diff --git a/test/scripts/extend/deployer.ts b/test/scripts/extend/deployer.ts index fc5d096cd2..100f929455 100644 --- a/test/scripts/extend/deployer.ts +++ b/test/scripts/extend/deployer.ts @@ -12,11 +12,11 @@ describe('Deployer', () => { d.get('test').should.exist; // no name - // @ts-ignore + // @ts-expect-error should.throw(() => d.register(), TypeError, 'name is required'); // no fn - // @ts-ignore + // @ts-expect-error should.throw(() => d.register('test'), TypeError, 'fn must be a function'); }); diff --git a/test/scripts/extend/filter.ts b/test/scripts/extend/filter.ts index a7f5adf0f0..015f69d9ba 100644 --- a/test/scripts/extend/filter.ts +++ b/test/scripts/extend/filter.ts @@ -30,7 +30,7 @@ describe('Filter', () => { f.list('after_post_render')[1].priority!.should.eql(50); // no fn - // @ts-ignore + // @ts-expect-error should.throw(() => f.register(), TypeError, 'fn must be a function'); }); @@ -73,13 +73,13 @@ describe('Filter', () => { it('unregister() - type is required', () => { const f = new Filter(); - // @ts-ignore + // @ts-expect-error should.throw(() => f.unregister(), 'type is required'); }); it('unregister() - fn must be a function', () => { const f = new Filter(); - // @ts-ignore + // @ts-expect-error should.throw(() => f.unregister('test'), 'fn must be a function'); }); diff --git a/test/scripts/extend/generator.ts b/test/scripts/extend/generator.ts index 37325838b6..f227e7fe0d 100644 --- a/test/scripts/extend/generator.ts +++ b/test/scripts/extend/generator.ts @@ -17,7 +17,7 @@ describe('Generator', () => { g.get('generator-0').should.exist; // no fn - // @ts-ignore + // @ts-expect-error should.throw(() => g.register('test'), TypeError, 'fn must be a function'); }); diff --git a/test/scripts/extend/helper.ts b/test/scripts/extend/helper.ts index 2bb5152c66..8664446748 100644 --- a/test/scripts/extend/helper.ts +++ b/test/scripts/extend/helper.ts @@ -12,11 +12,11 @@ describe('Helper', () => { h.get('test').should.exist; // no fn - // @ts-ignore + // @ts-expect-error should.throw(() => h.register('test'), TypeError, 'fn must be a function'); // no name - // @ts-ignore + // @ts-expect-error should.throw(() => h.register(), TypeError, 'name is required'); }); diff --git a/test/scripts/extend/injector.ts b/test/scripts/extend/injector.ts index 24d7c2106e..64fcccff2d 100644 --- a/test/scripts/extend/injector.ts +++ b/test/scripts/extend/injector.ts @@ -18,7 +18,7 @@ describe('Injector', () => { // no name try { - // @ts-ignore + // @ts-expect-error i.register(); } catch (err) { err.should.be @@ -52,7 +52,7 @@ describe('Injector', () => { const i = new Injector(); const str = ''; - // @ts-ignore + // @ts-expect-error i.register('foo', str); i.get('head_end').should.contains(str); diff --git a/test/scripts/extend/migrator.ts b/test/scripts/extend/migrator.ts index a284e04dae..c1a7ccb73c 100644 --- a/test/scripts/extend/migrator.ts +++ b/test/scripts/extend/migrator.ts @@ -12,11 +12,11 @@ describe('Migrator', () => { d.get('test').should.exist; // no name - // @ts-ignore + // @ts-expect-error should.throw(() => d.register(), TypeError, 'name is required'); // no fn - // @ts-ignore + // @ts-expect-error should.throw(() => d.register('test'), TypeError, 'fn must be a function'); }); diff --git a/test/scripts/extend/processor.ts b/test/scripts/extend/processor.ts index 0a2e5236a8..d67e052fdf 100644 --- a/test/scripts/extend/processor.ts +++ b/test/scripts/extend/processor.ts @@ -17,13 +17,13 @@ describe('Processor', () => { p.list()[1].should.exist; // more than one arg - // @ts-ignore + // @ts-expect-error p.register((a, b) => {}); p.list()[1].should.exist; // no fn - // @ts-ignore + // @ts-expect-error should.throw(() => p.register(), TypeError, 'fn must be a function'); }); diff --git a/test/scripts/extend/renderer.ts b/test/scripts/extend/renderer.ts index f06dd2cbdd..4432ee2aa9 100644 --- a/test/scripts/extend/renderer.ts +++ b/test/scripts/extend/renderer.ts @@ -1,6 +1,5 @@ import Renderer from '../../../lib/extend/renderer'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import chai from 'chai'; const should = chai.should(); @@ -10,7 +9,7 @@ describe('Renderer', () => { const r = new Renderer(); // name, output, fn - r.register('yaml', 'json', () => Promise.resolve()); + r.register('yaml', 'json', () => BluebirdPromise.resolve()); r.get('yaml').should.exist; r.get('yaml').output!.should.eql('json'); @@ -24,15 +23,15 @@ describe('Renderer', () => { r.get('yaml', true).output!.should.eql('json'); // no fn - // @ts-ignore + // @ts-expect-error should.throw(() => r.register('yaml', 'json'), TypeError, 'fn must be a function'); // no output - // @ts-ignore + // @ts-expect-error should.throw(() => r.register('yaml'), TypeError, 'output is required'); // no name - // @ts-ignore + // @ts-expect-error should.throw(() => r.register(), TypeError, 'name is required'); }); @@ -42,7 +41,7 @@ describe('Renderer', () => { // async r.register('yaml', 'json', (_data, _options, callback) => { callback && callback(null, 'foo'); - return Promise.resolve(); + return BluebirdPromise.resolve(); }); const yaml = await r.get('yaml')({}, {}); @@ -59,7 +58,7 @@ describe('Renderer', () => { const r = new Renderer(); function renderer(data, locals) { - return Promise.resolve(); + return BluebirdPromise.resolve(); } renderer.compile = data => { @@ -73,7 +72,7 @@ describe('Renderer', () => { it('getOutput()', () => { const r = new Renderer(); - r.register('yaml', 'json', () => Promise.resolve()); + r.register('yaml', 'json', () => BluebirdPromise.resolve()); r.getOutput('yaml').should.eql('json'); r.getOutput('.yaml').should.eql('json'); @@ -84,7 +83,7 @@ describe('Renderer', () => { it('isRenderable()', () => { const r = new Renderer(); - r.register('yaml', 'json', () => Promise.resolve()); + r.register('yaml', 'json', () => BluebirdPromise.resolve()); r.isRenderable('yaml').should.be.true; r.isRenderable('.yaml').should.be.true; @@ -95,7 +94,7 @@ describe('Renderer', () => { it('isRenderableSync()', () => { const r = new Renderer(); - r.register('yaml', 'json', () => Promise.resolve()); + r.register('yaml', 'json', () => BluebirdPromise.resolve()); r.isRenderableSync('yaml').should.be.false; @@ -110,7 +109,7 @@ describe('Renderer', () => { it('get()', () => { const r = new Renderer(); - r.register('yaml', 'json', () => Promise.resolve()); + r.register('yaml', 'json', () => BluebirdPromise.resolve()); r.get('yaml').should.exist; r.get('.yaml').should.exist; @@ -127,7 +126,7 @@ describe('Renderer', () => { it('list()', () => { const r = new Renderer(); - r.register('yaml', 'json', () => Promise.resolve()); + r.register('yaml', 'json', () => BluebirdPromise.resolve()); r.register('swig', 'html', () => {}, true); diff --git a/test/scripts/extend/tag.ts b/test/scripts/extend/tag.ts index cad5876d18..0407558a86 100644 --- a/test/scripts/extend/tag.ts +++ b/test/scripts/extend/tag.ts @@ -123,12 +123,12 @@ describe('Tag', () => { }); it('register() - name is required', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => tag.register(), 'name is required'); }); it('register() - fn must be a function', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => tag.register('test'), 'fn must be a function'); }); @@ -149,7 +149,7 @@ describe('Tag', () => { }); it('unregister() - name is required', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => tag.unregister(), 'name is required'); }); diff --git a/test/scripts/filters/backtick_code_block.ts b/test/scripts/filters/backtick_code_block.ts index 0dce3c3465..7a048301be 100644 --- a/test/scripts/filters/backtick_code_block.ts +++ b/test/scripts/filters/backtick_code_block.ts @@ -65,10 +65,8 @@ describe('Backtick code block', () => { const oldHljsCfg = hexo.config.highlight; const oldPrismCfg = hexo.config.prismjs; - // @ts-ignore - delete hexo.config.highlight; - // @ts-ignore - delete hexo.config.prismjs; + delete(hexo.config as any).highlight; + delete(hexo.config as any).prismjs; codeBlock(data); data.content.should.eql(content); diff --git a/test/scripts/filters/external_link.ts b/test/scripts/filters/external_link.ts index 414168593c..f0edddbd3f 100644 --- a/test/scripts/filters/external_link.ts +++ b/test/scripts/filters/external_link.ts @@ -127,7 +127,7 @@ describe('External link', () => { 'Hexo' ].join('\n'); - // @ts-ignore + // @ts-expect-error hexo.config.external_link.exclude = ['foo.com', 'bar.com']; const result = externalLink(content); diff --git a/test/scripts/filters/save_database.ts b/test/scripts/filters/save_database.ts index 030b9151cb..34c444f3dc 100644 --- a/test/scripts/filters/save_database.ts +++ b/test/scripts/filters/save_database.ts @@ -1,14 +1,13 @@ import Hexo from '../../../lib/hexo'; import { exists, unlink } from 'hexo-fs'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import saveDatabaseFilter from '../../../lib/plugins/filter/before_exit/save_database'; type SaveDatabaseFilterParams = Parameters type SaveDatabaseFilterReturn = ReturnType describe('Save database', () => { const hexo = new Hexo(); - const saveDatabase: (...args: SaveDatabaseFilterParams) => Promise = Promise.method(saveDatabaseFilter).bind(hexo); + const saveDatabase: (...args: SaveDatabaseFilterParams) => BluebirdPromise = BluebirdPromise.method(saveDatabaseFilter).bind(hexo); const dbPath = hexo.database.options.path; it('default', async () => { diff --git a/test/scripts/generators/page.ts b/test/scripts/generators/page.ts index 40acb39c17..16e2911b04 100644 --- a/test/scripts/generators/page.ts +++ b/test/scripts/generators/page.ts @@ -1,5 +1,4 @@ -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import pageGenerator from '../../../lib/plugins/generator/page'; import { NormalPostGenerator } from '../../../lib/types'; @@ -11,7 +10,7 @@ type PageGeneratorReturn = ReturnType; describe('page', () => { const hexo = new Hexo(__dirname, {silent: true}); const Page = hexo.model('Page'); - const generator: (...args: PageGeneratorParams) => Promise = Promise.method(pageGenerator.bind(hexo)); + const generator: (...args: PageGeneratorParams) => BluebirdPromise = BluebirdPromise.method(pageGenerator.bind(hexo)); const locals = (): any => { hexo.locals.invalidate(); diff --git a/test/scripts/generators/post.ts b/test/scripts/generators/post.ts index c99fb6922a..59ed7ca238 100644 --- a/test/scripts/generators/post.ts +++ b/test/scripts/generators/post.ts @@ -1,5 +1,4 @@ -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import postGenerator from '../../../lib/plugins/generator/post'; import { NormalPostGenerator } from '../../../lib/types'; @@ -11,7 +10,7 @@ type PostGeneratorReturn = ReturnType; describe('post', () => { const hexo = new Hexo(__dirname, {silent: true}); const Post = hexo.model('Post'); - const generator: (...args: PostGeneratorParams) => Promise = Promise.method(postGenerator.bind(hexo)); + const generator: (...args: PostGeneratorParams) => BluebirdPromise = BluebirdPromise.method(postGenerator.bind(hexo)); hexo.config.permalink = ':title/'; @@ -79,6 +78,6 @@ describe('post', () => { data[2].data.prev!._id!.should.eq(posts[0]._id); should.not.exist(data[2].data.next); - await Promise.all(posts.map(post => post.remove())); + await BluebirdPromise.all(posts.map(post => post.remove())); }); }); diff --git a/test/scripts/helpers/date.ts b/test/scripts/helpers/date.ts index f02e8fbaba..f7e8e38e2f 100644 --- a/test/scripts/helpers/date.ts +++ b/test/scripts/helpers/date.ts @@ -236,11 +236,11 @@ describe('date', () => { it('toMomentLocale', () => { (toMomentLocale(undefined) === undefined).should.be.true; // @ts-ignore - toMomentLocale(null).should.eql('en'); - toMomentLocale('').should.eql('en'); - toMomentLocale('en').should.eql('en'); - toMomentLocale('default').should.eql('en'); - toMomentLocale('zh-CN').should.eql('zh-cn'); - toMomentLocale('zh_CN').should.eql('zh-cn'); + toMomentLocale(null)!.should.eql('en'); + toMomentLocale('')!.should.eql('en'); + toMomentLocale('en')!.should.eql('en'); + toMomentLocale('default')!.should.eql('en'); + toMomentLocale('zh-CN')!.should.eql('zh-cn'); + toMomentLocale('zh_CN')!.should.eql('zh-cn'); }); }); diff --git a/test/scripts/helpers/feed_tag.ts b/test/scripts/helpers/feed_tag.ts index 03961a50b9..ba437e2fcb 100644 --- a/test/scripts/helpers/feed_tag.ts +++ b/test/scripts/helpers/feed_tag.ts @@ -39,19 +39,17 @@ describe('feed_tag', () => { }); it('invalid input - number', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => feed(123), 'path must be a string!'); }); it('invalid input - undefined', () => { delete ctx.config.feed; - // @ts-ignore feed().should.eql(''); }); it('invalid input - empty', () => { ctx.config.feed = {}; - // @ts-ignore feed().should.eql(''); }); diff --git a/test/scripts/helpers/partial.ts b/test/scripts/helpers/partial.ts index 85e7dbe35f..3f1d9c314f 100644 --- a/test/scripts/helpers/partial.ts +++ b/test/scripts/helpers/partial.ts @@ -1,7 +1,6 @@ import pathFn from 'path'; import { mkdirs, writeFile, rmdir } from 'hexo-fs'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import fragmentCache from '../../../lib/plugins/helper/fragment_cache'; import partialHelper from '../../../lib/plugins/helper/partial'; @@ -32,7 +31,7 @@ describe('partial', () => { const partial: (...args: PartialHelperParams) => PartialHelperReturn = partialHelper(hexo).bind(ctx); before(async () => { - await Promise.all([ + await BluebirdPromise.all([ mkdirs(themeDir), writeFile(hexo.config_path, 'theme: test') ]); @@ -87,7 +86,7 @@ describe('partial', () => { }); it('name must be a string', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => partial(), 'name must be a string!'); }); }); diff --git a/test/scripts/helpers/search_form.ts b/test/scripts/helpers/search_form.ts index 7de9cbaecc..4b52eface8 100644 --- a/test/scripts/helpers/search_form.ts +++ b/test/scripts/helpers/search_form.ts @@ -52,7 +52,7 @@ describe('search_form', () => { }); it('button - ignore incorrect type', () => { - // @ts-ignore + // @ts-expect-error searchForm({button: {}, text: 'Find'}).should.eql('
' + '' + '' diff --git a/test/scripts/helpers/tagcloud.ts b/test/scripts/helpers/tagcloud.ts index 3704694ee7..dd7237bbc9 100644 --- a/test/scripts/helpers/tagcloud.ts +++ b/test/scripts/helpers/tagcloud.ts @@ -1,5 +1,4 @@ -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import tagcloudHelper from '../../../lib/plugins/helper/tagcloud'; import chai from 'chai'; @@ -27,7 +26,7 @@ describe('tagcloud', () => { {source: 'boo', slug: 'boo'} ]); // TODO: Warehouse needs to add a mutex lock when writing data to avoid data sync problem - await Promise.all([ + await BluebirdPromise.all([ ['bcd'], ['bcd', 'cde'], ['bcd', 'cde', 'abc'], @@ -53,7 +52,7 @@ describe('tagcloud', () => { const hexo = new Hexo(__dirname); await hexo.init(); hexo.locals.invalidate(); - // @ts-ignore + // @ts-expect-error hexo.site = hexo.locals.toObject(); const tagcloud: (...args: TagcloudHelperParams) => TagcloudHelperReturn = tagcloudHelper.bind(hexo); diff --git a/test/scripts/hexo/hexo.ts b/test/scripts/hexo/hexo.ts index efbc72b9a6..50b5b2a287 100644 --- a/test/scripts/hexo/hexo.ts +++ b/test/scripts/hexo/hexo.ts @@ -1,7 +1,6 @@ import { sep, join } from 'path'; import { mkdirs, rmdir, unlink, writeFile } from 'hexo-fs'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import { spy } from 'sinon'; import { readStream } from '../../util'; import { full_url_for } from 'hexo-util'; @@ -231,7 +230,7 @@ describe('Hexo', () => { await hexo.watch(); await checkStream(route.get('test.txt'), body); // Test for first generation await writeFile(target, newBody); // Update the file - await Promise.delay(300); + await BluebirdPromise.delay(300); await checkStream(route.get('test.txt'), newBody); // Check the new route hexo.unwatch(); // Stop watching await unlink(target); // Delete the file @@ -300,9 +299,9 @@ describe('Hexo', () => { }); it('exit() - error handling - promise', () => { - return Promise.all([ + return BluebirdPromise.all([ hexo.exit({ foo: 'bar' }), - new Promise((resolve, reject) => { + new BluebirdPromise((resolve, reject) => { hexo.once('exit', err => { try { err.should.eql({ foo: 'bar' }); @@ -433,7 +432,7 @@ describe('Hexo', () => { beforeHook.calledOnce.should.be.true; afterHook.calledOnce.should.be.true; - await Promise.all([ + await BluebirdPromise.all([ checkStream(route.get('foo'), 'foo'), checkStream(route.get('bar'), 'bar'), checkStream(route.get('baz'), 'baz') @@ -533,7 +532,7 @@ describe('Hexo', () => { }); it('_generate() - return nothing in generator', async () => { - // @ts-ignore + // @ts-expect-error hexo.extend.generator.register('test_nothing', () => { // }); @@ -675,7 +674,7 @@ describe('Hexo', () => { it('execFilter() - promise', async () => { const fn = str => { - return new Promise((resolve, reject) => { + return new BluebirdPromise((resolve, reject) => { resolve(str + 'bar'); }); }; diff --git a/test/scripts/hexo/load_plugins.ts b/test/scripts/hexo/load_plugins.ts index 3446114e7e..aece55695f 100644 --- a/test/scripts/hexo/load_plugins.ts +++ b/test/scripts/hexo/load_plugins.ts @@ -2,8 +2,7 @@ import { join, dirname } from 'path'; import { writeFile, mkdir, rmdir, unlink } from 'hexo-fs'; import Hexo from '../../../lib/hexo'; import loadPlugins from '../../../lib/hexo/load_plugins'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import chai from 'chai'; const should = chai.should(); @@ -85,7 +84,7 @@ describe('Load plugins', () => { const name = 'hexo-plugin-test'; const path = join(hexo.plugin_dir, name, 'index.js'); - return Promise.all([ + return BluebirdPromise.all([ createPackageFile(name), writeFile(path, script) ]).then(() => loadPlugins(hexo)).then(() => { @@ -98,7 +97,7 @@ describe('Load plugins', () => { const name = 'hexo-async-plugin-test'; const path = join(hexo.plugin_dir, name, 'index.js'); - return Promise.all([ + return BluebirdPromise.all([ createPackageFile(name), writeFile(path, asyncScript) ]).then(() => loadPlugins(hexo)).then(() => { @@ -111,7 +110,7 @@ describe('Load plugins', () => { const name = '@some-scope/hexo-plugin-test'; const path = join(hexo.plugin_dir, name, 'index.js'); - return Promise.all([ + return BluebirdPromise.all([ createPackageFile(name), writeFile(path, script) ]).then(() => loadPlugins(hexo)).then(() => { @@ -124,7 +123,7 @@ describe('Load plugins', () => { const name = 'hexo-plugin-test'; const path = join(hexo.plugin_dir, name, 'index.js'); - return Promise.all([ + return BluebirdPromise.all([ createPackageFileWithDevDeps(name), writeFile(path, script) ]).then(() => loadPlugins(hexo)).then(() => { @@ -136,7 +135,7 @@ describe('Load plugins', () => { it('load plugins in the theme\'s package.json', async () => { const name = 'hexo-plugin-test'; const path = join(hexo.plugin_dir, name, 'index.js'); - return Promise.all([ + return BluebirdPromise.all([ createPackageFile(name, join(hexo.theme_dir, 'package.json')), writeFile(path, script) ]).then(() => loadPlugins(hexo)).then(() => { @@ -150,7 +149,7 @@ describe('Load plugins', () => { const name = 'hexo-theme-test_theme'; const path = join(hexo.plugin_dir, name, 'index.js'); - await Promise.all([ + await BluebirdPromise.all([ createPackageFile(name), writeFile(path, script) ]); @@ -166,7 +165,7 @@ describe('Load plugins', () => { const name = '@hexojs/hexo-theme-test_theme'; const path = join(hexo.plugin_dir, name, 'index.js'); - await Promise.all([ + await BluebirdPromise.all([ createPackageFile(name), writeFile(path, script) ]); @@ -182,7 +181,7 @@ describe('Load plugins', () => { const name = 'another-plugin'; const path = join(hexo.plugin_dir, name, 'index.js'); - await Promise.all([ + await BluebirdPromise.all([ createPackageFile(name), writeFile(path, script) ]); @@ -197,7 +196,7 @@ describe('Load plugins', () => { const name = '@types/hexo-test-plugin'; const path = join(hexo.plugin_dir, name, 'index.js'); - return Promise.all([ + return BluebirdPromise.all([ createPackageFile(name), writeFile(path, script) ]).then(() => loadPlugins(hexo)).then(() => { diff --git a/test/scripts/hexo/locals.ts b/test/scripts/hexo/locals.ts index 3fb483aef6..b28a2990b7 100644 --- a/test/scripts/hexo/locals.ts +++ b/test/scripts/hexo/locals.ts @@ -6,7 +6,7 @@ describe('Locals', () => { const locals = new Locals(); it('get() - name must be a string', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => locals.get(), 'name must be a string!'); }); @@ -26,12 +26,12 @@ describe('Locals', () => { }); it('set() - name must be a string', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => locals.set(), 'name must be a string!'); }); it('set() - value is required', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => locals.set('test'), 'value is required!'); }); @@ -45,7 +45,7 @@ describe('Locals', () => { }); it('remove() - name must be a string', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => locals.remove(), 'name must be a string!'); }); diff --git a/test/scripts/hexo/render.ts b/test/scripts/hexo/render.ts index b13a9d13f8..01e9cb2632 100644 --- a/test/scripts/hexo/render.ts +++ b/test/scripts/hexo/render.ts @@ -97,7 +97,7 @@ describe('Render', () => { it('render() - no path and text', async () => { try { - // @ts-ignore + // @ts-expect-error await hexo.render.render(); should.fail('Return value must be rejected'); } catch (err) { @@ -236,7 +236,7 @@ describe('Render', () => { }); it('renderSync() - no path and text', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => hexo.render.renderSync(), 'No input file or string!'); }); @@ -298,7 +298,7 @@ describe('Render', () => { const result = hexo.render.renderSync(data); filter.calledOnce.should.be.true; - // @ts-ignore + // @ts-expect-error sinonAssert.calledWith(filter, data.text, data); result.should.eql(data.text.trim()); diff --git a/test/scripts/hexo/router.ts b/test/scripts/hexo/router.ts index 5683a13636..8564500753 100644 --- a/test/scripts/hexo/router.ts +++ b/test/scripts/hexo/router.ts @@ -1,5 +1,4 @@ -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import { Readable } from 'stream'; import { join } from 'path'; import crypto from 'crypto'; @@ -20,7 +19,7 @@ describe('Router', () => { } function checksum(stream) { - return new Promise((resolve, reject) => { + return new BluebirdPromise((resolve, reject) => { const hash = crypto.createHash('sha1'); stream.on('readable', () => { @@ -58,7 +57,7 @@ describe('Router', () => { }); it('format() - path must be a string', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => router.format(() => {}), 'path must be a string!'); }); @@ -111,12 +110,12 @@ describe('Router', () => { }); it('set() - path must be a string', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => router.set(), 'path must be a string!'); }); it('set() - data is required', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => router.set('test'), 'data is required!'); }); @@ -154,7 +153,7 @@ describe('Router', () => { router.set('test', () => createReadStream(path)); - return Promise.all([ + return BluebirdPromise.all([ checksum(router.get('test')), checksum(createReadStream(path)) ]).then((data: any) => { @@ -163,7 +162,7 @@ describe('Router', () => { }); it('get() - path must be a string', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => router.get(), 'path must be a string!'); }); @@ -192,7 +191,7 @@ describe('Router', () => { }); it('isModified() - path must be a string', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => router.isModified(), 'path must be a string!'); }); @@ -209,7 +208,7 @@ describe('Router', () => { }); it('remove() - path must be a string', () => { - // @ts-ignore + // @ts-expect-error should.throw(() => router.remove(), 'path must be a string!'); }); }); diff --git a/test/scripts/hexo/validate_config.ts b/test/scripts/hexo/validate_config.ts index c414c2a68d..87ec01d90e 100644 --- a/test/scripts/hexo/validate_config.ts +++ b/test/scripts/hexo/validate_config.ts @@ -17,8 +17,7 @@ describe('Validate config', () => { }); it('config.url - undefined', () => { - // @ts-ignore - delete hexo.config.url; + delete(hexo.config as any).url; try { validateConfig(hexo); @@ -30,7 +29,7 @@ describe('Validate config', () => { }); it('config.url - wrong type', () => { - // @ts-ignore + // @ts-expect-error hexo.config.url = true; try { @@ -68,8 +67,7 @@ describe('Validate config', () => { }); it('config.root - undefined', () => { - // @ts-ignore - delete hexo.config.root; + delete(hexo.config as any).root; try { validateConfig(hexo); @@ -81,7 +79,7 @@ describe('Validate config', () => { }); it('config.root - wrong type', () => { - // @ts-ignore + // @ts-expect-error hexo.config.root = true; try { diff --git a/test/scripts/models/moment.ts b/test/scripts/models/moment.ts index 19fa102b81..f675d93150 100644 --- a/test/scripts/models/moment.ts +++ b/test/scripts/models/moment.ts @@ -50,7 +50,7 @@ describe('SchemaTypeMoment', () => { it('validate() - required', () => { const type = new SchemaTypeMoment('test', {required: true}); - // @ts-ignore + // @ts-expect-error should.throw(() => type.validate(), '`test` is required!'); }); @@ -70,7 +70,7 @@ describe('SchemaTypeMoment', () => { }); it('parse()', () => { - type.parse('2014-11-03T07:45:41.237Z').should.eql(moment('2014-11-03T07:45:41.237Z')); + type.parse('2014-11-03T07:45:41.237Z')!.should.eql(moment('2014-11-03T07:45:41.237Z')); should.not.exist(type.parse()); }); diff --git a/test/scripts/models/post.ts b/test/scripts/models/post.ts index 258d5dac6e..6c02b54246 100644 --- a/test/scripts/models/post.ts +++ b/test/scripts/models/post.ts @@ -1,6 +1,5 @@ import { join, sep } from 'path'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import { full_url_for } from 'hexo-util'; import Hexo from '../../../lib/hexo'; import chai from 'chai'; @@ -239,7 +238,7 @@ describe('Post', () => { it('setTags() - sync problem', () => Post.insert([ {source: 'foo.md', slug: 'foo'}, {source: 'bar.md', slug: 'bar'} - ]).then(posts => Promise.all([ + ]).then(posts => BluebirdPromise.all([ posts[0].setTags(['foo', 'bar']), posts[1].setTags(['bar', 'baz']) ]).thenReturn(posts)).then(posts => { @@ -306,7 +305,7 @@ describe('Post', () => { postA.categories.map(cat => cat._id).should.eql(postB.categories.map(cat => cat._id)); - return Promise.all([ + return BluebirdPromise.all([ Post.removeById(postIdA), Post.removeById(postIdB) ]); @@ -344,7 +343,7 @@ describe('Post', () => { postCategoriesA.should.not.include(catId); }); - return Promise.all([ + return BluebirdPromise.all([ Post.removeById(postIdA), Post.removeById(postIdB) ]); @@ -446,7 +445,7 @@ describe('Post', () => { it('remove related assets when a post is removed', () => Post.insert({ source: 'foo.md', slug: 'bar' - }).then(post => Promise.all([ + }).then(post => BluebirdPromise.all([ Asset.insert({_id: 'foo', path: 'foo'}), Asset.insert({_id: 'bar', path: 'bar'}), Asset.insert({_id: 'baz', path: 'bar'}) diff --git a/test/scripts/processors/common.ts b/test/scripts/processors/common.ts index 444b073c7f..ed07d371ac 100644 --- a/test/scripts/processors/common.ts +++ b/test/scripts/processors/common.ts @@ -33,11 +33,11 @@ describe('common', () => { const d = new Date(); should.not.exist(toDate()); - toDate(m).should.eql(m); - toDate(d).should.eql(d); - toDate(1e8).should.eql(new Date(1e8)); - toDate('2014-04-25T01:32:21.196Z').should.eql(new Date('2014-04-25T01:32:21.196Z')); - toDate('Apr 24 2014').should.eql(new Date(2014, 3, 24)); + toDate(m)!.should.eql(m); + toDate(d)!.should.eql(d); + toDate(1e8)!.should.eql(new Date(1e8)); + toDate('2014-04-25T01:32:21.196Z')!.should.eql(new Date('2014-04-25T01:32:21.196Z')); + toDate('Apr 24 2014')!.should.eql(new Date(2014, 3, 24)); should.not.exist(toDate('foo')); }); diff --git a/test/scripts/processors/data.ts b/test/scripts/processors/data.ts index 95687afce9..0c08476d6d 100644 --- a/test/scripts/processors/data.ts +++ b/test/scripts/processors/data.ts @@ -1,5 +1,4 @@ -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import { mkdirs, rmdir, unlink, writeFile } from 'hexo-fs'; import { join } from 'path'; import Hexo from '../../../lib/hexo'; @@ -11,7 +10,7 @@ describe('data', () => { const baseDir = join(__dirname, 'data_test'); const hexo = new Hexo(baseDir); const processor = data(hexo); - const process = Promise.method(processor.process).bind(hexo); + const process = BluebirdPromise.method(processor.process).bind(hexo); const { source } = hexo; const { File } = source; const Data = hexo.model('Data'); @@ -114,7 +113,7 @@ describe('data', () => { type: 'update' }); - await Promise.all([ + await BluebirdPromise.all([ writeFile(file.source, body), Data.insert({ _id: 'users', diff --git a/test/scripts/processors/post.ts b/test/scripts/processors/post.ts index c19f2f2c9c..d3ebdae703 100644 --- a/test/scripts/processors/post.ts +++ b/test/scripts/processors/post.ts @@ -1,8 +1,7 @@ import { join } from 'path'; import { mkdirs, rmdir, unlink, writeFile } from 'hexo-fs'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import defaultConfig from '../../../lib/hexo/default_config'; import Hexo from '../../../lib/hexo'; import posts from '../../../lib/plugins/processor/post'; @@ -17,7 +16,7 @@ describe('post', () => { const baseDir = join(__dirname, 'post_test'); const hexo = new Hexo(baseDir); const post = posts(hexo); - const process: (...args: PostParams) => Promise = Promise.method(post.process.bind(hexo)); + const process: (...args: PostParams) => BluebirdPromise = BluebirdPromise.method(post.process.bind(hexo)); const { pattern } = post; const { source } = hexo; const { File } = source; @@ -149,7 +148,7 @@ describe('post', () => { asset.modified.should.be.true; asset.renderable.should.be.false; - await Promise.all([ + await BluebirdPromise.all([ Post.removeById(postId), unlink(file.source) ]); @@ -184,7 +183,7 @@ describe('post', () => { const asset = PostAsset.findById(id); asset.modified.should.be.true; - await Promise.all([ + await BluebirdPromise.all([ Post.removeById(postId), unlink(file.source) ]); @@ -219,7 +218,7 @@ describe('post', () => { const asset = PostAsset.findById(id); asset.modified.should.be.false; - await Promise.all([ + await BluebirdPromise.all([ Post.removeById(postId), unlink(file.source) ]); @@ -311,7 +310,7 @@ describe('post', () => { const id = join('source/', file.path); - await Promise.all([ + await BluebirdPromise.all([ writeFile(file.source, 'test'), PostAsset.insert({ _id: id, @@ -353,7 +352,7 @@ describe('post', () => { post.slug.should.eql('foo'); post.published.should.be.true; - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -382,7 +381,7 @@ describe('post', () => { post._id!.should.eql(id); post.title.should.eql('New world'); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -468,7 +467,7 @@ describe('post', () => { post.slug.should.eql('foo'); post.date.format('YYYY-MM-DD').should.eql('2006-01-02'); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -496,7 +495,7 @@ describe('post', () => { post.slug.should.eql('20060102'); post.date.format('YYYY-MM-DD').should.eql('2006-01-02'); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -523,7 +522,7 @@ describe('post', () => { post.lang.should.eql('zh'); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -550,7 +549,7 @@ describe('post', () => { post.slug.should.eql('foo'); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -576,7 +575,7 @@ describe('post', () => { post.published.should.be.false; - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -602,7 +601,7 @@ describe('post', () => { post.published.should.be.false; - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -629,7 +628,7 @@ describe('post', () => { post.date.toDate().setMilliseconds(0).should.eql(stats.birthtime.setMilliseconds(0)); post.updated.toDate().setMilliseconds(0).should.eql(stats.mtime.setMilliseconds(0)); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -659,7 +658,7 @@ describe('post', () => { post.updated.toDate().setMilliseconds(0).should.eql(post.date.toDate().setMilliseconds(0)); post.updated.toDate().setMilliseconds(0).should.not.eql(stats.mtime.setMilliseconds(0)); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -689,7 +688,7 @@ describe('post', () => { post.updated.toDate().setMilliseconds(0).should.eql(stats.mtime.setMilliseconds(0)); post.updated.toDate().setMilliseconds(0).should.not.eql(post.date.toDate().setMilliseconds(0)); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -716,7 +715,7 @@ describe('post', () => { should.not.exist(post.updated); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -749,7 +748,7 @@ describe('post', () => { should.not.exist(post.photo); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -777,7 +776,7 @@ describe('post', () => { 'https://hexo.io/foo.jpg' ]); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -799,7 +798,7 @@ describe('post', () => { post.title.should.eql(''); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -828,7 +827,7 @@ describe('post', () => { should.not.exist(post.category); post.categories.map(item => item.name).should.eql(['foo', 'bar']); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -854,7 +853,7 @@ describe('post', () => { post.categories.map(item => item.name).should.eql(['foo']); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -882,7 +881,7 @@ describe('post', () => { post.categories.map(item => item.name).should.eql(['foo', 'bar', 'baz']); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -911,7 +910,7 @@ describe('post', () => { should.not.exist(post.tag); post.tags.map(item => item.name).should.have.members(['foo', 'bar']); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -937,7 +936,7 @@ describe('post', () => { post.tags.map(item => item.name).should.eql(['foo']); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -976,7 +975,7 @@ describe('post', () => { }; }); - await Promise.all([ + await BluebirdPromise.all([ writeFile(file.source, body), ...assetFiles.map(obj => writeFile(obj.path, obj.contents)) ]); @@ -1000,7 +999,7 @@ describe('post', () => { post.remove(); - await Promise.all([ + await BluebirdPromise.all([ unlink(file.source), ...assetFiles.map(obj => unlink(obj.path)) ]); @@ -1026,7 +1025,7 @@ describe('post', () => { const assetId = join('source/_posts/foo/', 'bar.jpg'); const assetPath = join(hexo.base_dir, assetId); - await Promise.all([ + await BluebirdPromise.all([ writeFile(file.source, body), writeFile(assetPath, '') ]); @@ -1046,7 +1045,7 @@ describe('post', () => { hexo.config.render_drafts = false; - await Promise.all([ + await BluebirdPromise.all([ post.remove(), unlink(file.source), unlink(assetPath) @@ -1073,7 +1072,7 @@ describe('post', () => { const assetId = join('source/_posts/foo/', 'bar.jpg'); const assetPath = join(hexo.base_dir, assetId); - await Promise.all([ + await BluebirdPromise.all([ writeFile(file.source, body), writeFile(assetPath, '') ]); @@ -1091,7 +1090,7 @@ describe('post', () => { post.published.should.be.false; should.not.exist(PostAsset.findById(assetId)); - await Promise.all([ + await BluebirdPromise.all([ post.remove(), unlink(file.source), unlink(assetPath) @@ -1112,7 +1111,7 @@ describe('post', () => { const assetId = join('source/_posts/foo/', 'bar.jpg'); const assetPath = join(hexo.base_dir, assetId); - await Promise.all([ + await BluebirdPromise.all([ writeFile(file.source, ''), writeFile(assetPath, '') ]); @@ -1121,7 +1120,7 @@ describe('post', () => { should.not.exist(PostAsset.findById(assetId)); post.remove(); - await Promise.all([ + await BluebirdPromise.all([ unlink(file.source), unlink(assetPath) ]); @@ -1149,7 +1148,7 @@ describe('post', () => { post.date.format(dateFormat).should.eql('2014-04-24 00:00:00'); post.updated.format(dateFormat).should.eql('2015-05-05 00:00:00'); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -1178,7 +1177,7 @@ describe('post', () => { post.date.toDate().setMilliseconds(0).should.eql(stats.birthtime.setMilliseconds(0)); post.updated.toDate().setMilliseconds(0).should.eql(stats.mtime.setMilliseconds(0)); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -1259,7 +1258,7 @@ describe('post', () => { post.__permalink.should.eql('foooo'); - return Promise.all([ + return BluebirdPromise.all([ post.remove(), unlink(file.source) ]); @@ -1281,7 +1280,7 @@ describe('post', () => { type: 'create' }); - await Promise.all([ + await BluebirdPromise.all([ writeFile(file.source, 'test'), writeFile(assetFile.source, 'test') ]); @@ -1292,7 +1291,7 @@ describe('post', () => { hexo.config.post_asset_folder = false; - return Promise.all([ + return BluebirdPromise.all([ unlink(file.source), unlink(assetFile.source), post.remove(), @@ -1317,7 +1316,7 @@ describe('post', () => { type: 'create' }); - await Promise.all([ + await BluebirdPromise.all([ writeFile(file.source, 'test'), writeFile(assetFile.source, 'test') ]); @@ -1329,7 +1328,7 @@ describe('post', () => { hexo.config.post_asset_folder = false; hexo.config.skip_render = '' as any; - return Promise.all([ + return BluebirdPromise.all([ unlink(file.source), unlink(assetFile.source), post.remove(), diff --git a/test/scripts/tags/asset_img.ts b/test/scripts/tags/asset_img.ts index 78e841b1d2..4f4a2a74c2 100644 --- a/test/scripts/tags/asset_img.ts +++ b/test/scripts/tags/asset_img.ts @@ -1,5 +1,4 @@ -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import tagAssetImg from '../../../lib/plugins/tag/asset_img'; import chai from 'chai'; @@ -24,7 +23,7 @@ describe('asset_img', () => { })).then(post_ => { post = post_; - return Promise.all([ + return BluebirdPromise.all([ PostAsset.insert({ _id: 'bar', slug: 'bar', diff --git a/test/scripts/tags/asset_link.ts b/test/scripts/tags/asset_link.ts index d03ec1fdb9..3cb73b30b1 100644 --- a/test/scripts/tags/asset_link.ts +++ b/test/scripts/tags/asset_link.ts @@ -1,5 +1,4 @@ -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import tagAssetLink from '../../../lib/plugins/tag/asset_link'; import chai from 'chai'; @@ -24,7 +23,7 @@ describe('asset_link', () => { })).then(post_ => { post = post_; - return Promise.all([ + return BluebirdPromise.all([ PostAsset.insert({ _id: 'bar', slug: 'bar', diff --git a/test/scripts/tags/asset_path.ts b/test/scripts/tags/asset_path.ts index ad84a5ff11..2a78f4d2ab 100644 --- a/test/scripts/tags/asset_path.ts +++ b/test/scripts/tags/asset_path.ts @@ -1,5 +1,4 @@ -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import tagAssetPath from '../../../lib/plugins/tag/asset_path'; import chai from 'chai'; @@ -24,7 +23,7 @@ describe('asset_path', () => { })).then(post_ => { post = post_; - return Promise.all([ + return BluebirdPromise.all([ PostAsset.insert({ _id: 'bar', slug: 'bar', diff --git a/test/scripts/tags/include_code.ts b/test/scripts/tags/include_code.ts index bbbb37e7fd..62e95b0abe 100644 --- a/test/scripts/tags/include_code.ts +++ b/test/scripts/tags/include_code.ts @@ -1,8 +1,7 @@ import { join } from 'path'; import { rmdir, writeFile } from 'hexo-fs'; import { highlight, prismHighlight } from 'hexo-util'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import tagIncludeCode from '../../../lib/plugins/tag/include_code'; import chai from 'chai'; @@ -11,7 +10,7 @@ const should = chai.should(); describe('include_code', () => { const hexo = new Hexo(join(__dirname, 'include_code_test')); require('../../../lib/plugins/highlight/')(hexo); - const includeCode = Promise.method(tagIncludeCode(hexo)); + const includeCode = BluebirdPromise.method(tagIncludeCode(hexo)) as (arg1: string[]) => BluebirdPromise; const path = join(hexo.source_dir, hexo.config.code_dir, 'test.js'); const defaultCfg = JSON.parse(JSON.stringify(hexo.config)); diff --git a/test/scripts/theme_processors/config.ts b/test/scripts/theme_processors/config.ts index 1a3bdb5b7c..069e6cb1cd 100644 --- a/test/scripts/theme_processors/config.ts +++ b/test/scripts/theme_processors/config.ts @@ -1,8 +1,7 @@ import { spy, assert as sinonAssert } from 'sinon'; import { join } from 'path'; import { mkdirs, rmdir, unlink, writeFile} from 'hexo-fs'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import { config } from '../../../lib/theme/processors/config'; import chai from 'chai'; @@ -12,7 +11,7 @@ type ConfigReturn = ReturnType describe('config', () => { const hexo = new Hexo(join(__dirname, 'config_test'), {silent: true}); - const process: (...args: ConfigParams) => Promise = Promise.method(config.process.bind(hexo)); + const process: (...args: ConfigParams) => BluebirdPromise = BluebirdPromise.method(config.process.bind(hexo)); const themeDir = join(hexo.base_dir, 'themes', 'test'); function newFile(options) { @@ -21,7 +20,7 @@ describe('config', () => { } before(async () => { - await Promise.all([ + await BluebirdPromise.all([ mkdirs(themeDir), writeFile(hexo.config_path, 'theme: test') ]); diff --git a/test/scripts/theme_processors/i18n.ts b/test/scripts/theme_processors/i18n.ts index edb1d6b3c4..e4ee9b0417 100644 --- a/test/scripts/theme_processors/i18n.ts +++ b/test/scripts/theme_processors/i18n.ts @@ -1,7 +1,6 @@ import { join } from 'path'; import { mkdirs, rmdir, unlink, writeFile } from 'hexo-fs'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import { i18n } from '../../../lib/theme/processors/i18n'; import chai from 'chai'; @@ -11,7 +10,7 @@ type I18nReturn = ReturnType describe('i18n', () => { const hexo = new Hexo(join(__dirname, 'config_test'), {silent: true}); - const process: (...args: I18nParams) => Promise = Promise.method(i18n.process.bind(hexo)); + const process: (...args: I18nParams) => BluebirdPromise = BluebirdPromise.method(i18n.process.bind(hexo)); const themeDir = join(hexo.base_dir, 'themes', 'test'); function newFile(options) { @@ -26,7 +25,7 @@ describe('i18n', () => { } before(async () => { - await Promise.all([ + await BluebirdPromise.all([ mkdirs(themeDir), writeFile(hexo.config_path, 'theme: test') ]); diff --git a/test/scripts/theme_processors/source.ts b/test/scripts/theme_processors/source.ts index 5d9343b239..286a9c77dc 100644 --- a/test/scripts/theme_processors/source.ts +++ b/test/scripts/theme_processors/source.ts @@ -1,7 +1,6 @@ import { join } from 'path'; import { mkdirs, rmdir, unlink, writeFile } from 'hexo-fs'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import { source } from '../../../lib/theme/processors/source'; import chai from 'chai'; @@ -11,7 +10,7 @@ type SourceReturn = ReturnType describe('source', () => { const hexo = new Hexo(join(__dirname, 'source_test'), {silent: true}); - const process: (...args: SourceParams) => Promise = Promise.method(source.process.bind(hexo)); + const process: (...args: SourceParams) => BluebirdPromise = BluebirdPromise.method(source.process.bind(hexo)); const themeDir = join(hexo.base_dir, 'themes', 'test'); const Asset = hexo.model('Asset'); @@ -26,7 +25,7 @@ describe('source', () => { } before(async () => { - await Promise.all([ + await BluebirdPromise.all([ mkdirs(themeDir), writeFile(hexo.config_path, 'theme: test') ]); @@ -79,7 +78,7 @@ describe('source', () => { const id = join('themes/test/', file.path); - await Promise.all([ + await BluebirdPromise.all([ writeFile(file.source, 'test'), Asset.insert({ _id: id, @@ -92,7 +91,7 @@ describe('source', () => { asset.modified.should.be.true; - await Promise.all([ + await BluebirdPromise.all([ unlink(file.source), Asset.removeById(id) ]); @@ -106,7 +105,7 @@ describe('source', () => { const id = join('themes/test/', file.path); - await Promise.all([ + await BluebirdPromise.all([ writeFile(file.source, 'test'), Asset.insert({ _id: id, @@ -118,7 +117,7 @@ describe('source', () => { const asset = Asset.findById(id); asset.modified.should.be.false; - await Promise.all([ + await BluebirdPromise.all([ unlink(file.source), Asset.removeById(id) ]); diff --git a/test/scripts/theme_processors/view.ts b/test/scripts/theme_processors/view.ts index 1b7c254af9..2d87a71782 100644 --- a/test/scripts/theme_processors/view.ts +++ b/test/scripts/theme_processors/view.ts @@ -1,7 +1,6 @@ import { join } from 'path'; import { mkdirs, rmdir, unlink, writeFile } from 'hexo-fs'; -// @ts-ignore -import Promise from 'bluebird'; +import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import { view } from '../../../lib/theme/processors/view'; import chai from 'chai'; @@ -12,7 +11,7 @@ type ViewReturn = ReturnType describe('view', () => { const hexo = new Hexo(join(__dirname, 'view_test'), {silent: true}); - const process: (...args: ViewParams) => Promise = Promise.method(view.process.bind(hexo)); + const process: (...args: ViewParams) => BluebirdPromise = BluebirdPromise.method(view.process.bind(hexo)); const themeDir = join(hexo.base_dir, 'themes', 'test'); hexo.env.init = true; @@ -28,7 +27,7 @@ describe('view', () => { } before(async () => { - await Promise.all([ + await BluebirdPromise.all([ mkdirs(themeDir), writeFile(hexo.config_path, 'theme: test') ]); From f2e2326bdd9c2ea5892bcc1b02a09a0ca4eb7da3 Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Tue, 30 Apr 2024 20:38:35 +0800 Subject: [PATCH 04/10] docs: code annotation --- lib/hexo/index.ts | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/lib/hexo/index.ts b/lib/hexo/index.ts index 255d801ce6..93337a5fac 100644 --- a/lib/hexo/index.ts +++ b/lib/hexo/index.ts @@ -111,13 +111,37 @@ function debounce(func: () => void, wait: number): () => void { } interface Args { + + /** + * Enable debug mode. Display debug messages in the terminal and save debug.log in the root directory. + */ debug?: boolean; + + /** + * Enable safe mode. Don’t load any plugins. + */ safe?: boolean; + + /** + * Enable silent mode. Don’t display any messages in the terminal. + */ silent?: boolean; + + /** + * Enable to add drafts to the posts list. + */ draft?: boolean; + + /** + * Enable to add drafts to the posts list. + */ drafts?: boolean; _?: string[]; output?: string; + + /** + * Specify the path of the configuration file. + */ config?: string; [key: string]: any; } @@ -407,6 +431,11 @@ class Hexo extends EventEmitter { }); } + /** + * Load configuration and plugins. + * @returns {Promise} + * @link https://hexo.io/api#Initialize + */ init(): Promise { this.log.debug('Hexo version: %s', magenta(this.version)); this.log.debug('Working directory: %s', magenta(tildify(this.base_dir))); @@ -434,6 +463,14 @@ class Hexo extends EventEmitter { }); } + /** + * Call any console command explicitly. + * @param name + * @param args + * @param callback + * @returns {Promise} + * @link https://hexo.io/api#Execute-Commands + */ call(name: string, callback?: NodeJSLikeCallback): Promise; call(name: string, args: object, callback?: NodeJSLikeCallback): Promise; call(name: string, args?: object | NodeJSLikeCallback, callback?: NodeJSLikeCallback): Promise { @@ -500,6 +537,12 @@ class Hexo extends EventEmitter { return args.draft || args.drafts || this.config.render_drafts; } + /** + * Load all files in the source folder as well as the theme data. + * @param callback + * @returns {Promise} + * @link https://hexo.io/api#Load-Files + */ load(callback?: NodeJSLikeCallback): Promise { return loadDatabase(this).then(() => { this.log.info('Start processing'); @@ -514,6 +557,13 @@ class Hexo extends EventEmitter { }).asCallback(callback); } + /** + * Load all files in the source folder as well as the theme data. + * Start watching for file changes continuously. + * @param callback + * @returns {Promise} + * @link https://hexo.io/api#Load-Files + */ watch(callback?: NodeJSLikeCallback): Promise { let useCache = false; const { cache } = Object.assign({ @@ -666,6 +716,12 @@ class Hexo extends EventEmitter { }); } + /** + * Exit gracefully and finish up important things such as saving the database. + * @param err + * @returns {Promise} + * @link https://hexo.io/api/#Exit + */ exit(err?: any): Promise { if (err) { this.log.fatal( From fa58a322e302aa7a429a9c5066af1e9eb5835a92 Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Tue, 30 Apr 2024 20:59:29 +0800 Subject: [PATCH 05/10] docs: code annotation --- lib/extend/console.ts | 3 +++ lib/extend/deployer.ts | 3 +++ lib/extend/filter.ts | 4 ++++ lib/extend/generator.ts | 3 +++ lib/extend/helper.ts | 4 +++- lib/extend/injector.ts | 4 ++++ lib/extend/migrator.ts | 3 +++ lib/extend/processor.ts | 4 ++++ lib/extend/renderer.ts | 3 +++ lib/extend/tag.ts | 3 +++ 10 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/extend/console.ts b/lib/extend/console.ts index 0c32af063c..6e27f6c70b 100644 --- a/lib/extend/console.ts +++ b/lib/extend/console.ts @@ -33,6 +33,9 @@ interface Alias { [abbreviation: string]: string } +/** + * The console forms the bridge between Hexo and its users. It registers and describes the available console commands. + */ class Console { public store: Store; public alias: Alias; diff --git a/lib/extend/deployer.ts b/lib/extend/deployer.ts index 5014433c4e..c6def5cfc5 100644 --- a/lib/extend/deployer.ts +++ b/lib/extend/deployer.ts @@ -11,6 +11,9 @@ interface Store { [key: string]: StoreFunction } +/** + * A deployer helps users quickly deploy their site to a remote server without complicated commands. + */ class Deployer { public store: Store; diff --git a/lib/extend/filter.ts b/lib/extend/filter.ts index 98b34de1f3..a05ef42a49 100644 --- a/lib/extend/filter.ts +++ b/lib/extend/filter.ts @@ -21,6 +21,10 @@ interface Store { [key: string]: StoreFunction[] } +/** + * A filter is used to modify some specified data. Hexo passes data to filters in sequence and the filters then modify the data one after the other. + * This concept was borrowed from WordPress. + */ class Filter { public store: Store; diff --git a/lib/extend/generator.ts b/lib/extend/generator.ts index 6370f5029e..de4add89a2 100644 --- a/lib/extend/generator.ts +++ b/lib/extend/generator.ts @@ -23,6 +23,9 @@ interface Store { [key: string]: StoreFunction } +/** + * A generator builds routes based on processed files. + */ class Generator { public id: number; public store: Store; diff --git a/lib/extend/helper.ts b/lib/extend/helper.ts index f167282371..65932a6184 100644 --- a/lib/extend/helper.ts +++ b/lib/extend/helper.ts @@ -6,7 +6,9 @@ interface Store { [key: string]: StoreFunction } - +/** + * A helper makes it easy to quickly add snippets to your templates. We recommend using helpers instead of templates when you’re dealing with more complicated code. + */ class Helper { public store: Store; diff --git a/lib/extend/injector.ts b/lib/extend/injector.ts index edb4a45094..3c0dc5f229 100644 --- a/lib/extend/injector.ts +++ b/lib/extend/injector.ts @@ -8,6 +8,10 @@ type Store = { }; }; +/** + * An injector is used to add static code snippet to the `` or/and `` of generated HTML files. + * Hexo run injector before `after_render:html` filter is executed. + */ class Injector { public store: Store; public cache: any; diff --git a/lib/extend/migrator.ts b/lib/extend/migrator.ts index ce5ae77544..30fb412da7 100644 --- a/lib/extend/migrator.ts +++ b/lib/extend/migrator.ts @@ -9,6 +9,9 @@ interface Store { [key: string]: StoreFunction } +/** + * A migrator helps users migrate from other systems to Hexo. + */ class Migrator { public store: Store; diff --git a/lib/extend/processor.ts b/lib/extend/processor.ts index ce73da1031..f2f2be60e8 100644 --- a/lib/extend/processor.ts +++ b/lib/extend/processor.ts @@ -12,6 +12,10 @@ type Store = { }[]; type patternType = Exclude[0], ((str: string) => string)>; + +/** + * A processor is used to process source files in the `source` folder. + */ class Processor { public store: Store; diff --git a/lib/extend/renderer.ts b/lib/extend/renderer.ts index 530b071e18..18413f3e14 100644 --- a/lib/extend/renderer.ts +++ b/lib/extend/renderer.ts @@ -50,6 +50,9 @@ interface Store { [key: string]: StoreFunction; } +/** + * A renderer is used to render content. + */ class Renderer { public store: Store; public storeSync: SyncStore; diff --git a/lib/extend/tag.ts b/lib/extend/tag.ts index b9648d3297..278a96deb5 100644 --- a/lib/extend/tag.ts +++ b/lib/extend/tag.ts @@ -200,6 +200,9 @@ type RegisterOptions = { ends?: boolean; } +/** + * A tag allows users to quickly and easily insert snippets into their posts. + */ class Tag { public env: Environment; public source: string; From add7916f71a5cae598f1b3e340ca919ac26c6190 Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Sat, 11 Jan 2025 15:54:50 +0800 Subject: [PATCH 06/10] refactor: refactor type --- lib/box/index.ts | 46 +++++++++++++++++++++++----------------- lib/hexo/load_plugins.ts | 12 +++++------ lib/hexo/locals.ts | 8 +++---- lib/hexo/render.ts | 2 +- lib/theme/index.ts | 5 ----- 5 files changed, 37 insertions(+), 36 deletions(-) diff --git a/lib/box/index.ts b/lib/box/index.ts index 9ac0703f7a..aeff5b4012 100644 --- a/lib/box/index.ts +++ b/lib/box/index.ts @@ -17,20 +17,26 @@ interface Processor { process: (file?: File) => any; } +interface BoxOptions { + persistent: boolean; + awaitWriteFinish: { stabilityThreshold: number }; + ignored: RegExp[]; + [key: string]: any; +} + class Box extends EventEmitter { - public options: any; + public options: BoxOptions; public context: Hexo; public base: string; public processors: Processor[]; - public _processingFiles: any; - public watcher: any; + public _processingFiles: Record; + public watcher: Awaited> | null; public Cache: any; // TODO: replace runtime class _File public File: any; - public ignore: any[]; - public source: any; + public ignore: string[]; - constructor(ctx: Hexo, base: string, options?: object) { + constructor(ctx: Hexo, base: string, options?: any) { super(); this.options = Object.assign({ @@ -51,7 +57,7 @@ class Box extends EventEmitter { this.watcher = null; this.Cache = ctx.model('Cache'); this.File = this._createFileClass(); - let targets = this.options.ignored || []; + let targets = this.options.ignored as unknown as string[] || []; if (ctx.config.ignore && ctx.config.ignore.length) { targets = targets.concat(ctx.config.ignore); } @@ -65,13 +71,13 @@ class Box extends EventEmitter { class _File extends File { public box: Box; - render(options?: object) { + render(options?: any) { return ctx.render.render({ path: this.source }, options); } - renderSync(options?: object) { + renderSync(options?: any) { return ctx.render.renderSync({ path: this.source }, options); @@ -84,8 +90,8 @@ class Box extends EventEmitter { } addProcessor(pattern: (...args: any[]) => any): void; - addProcessor(pattern: string | RegExp | Pattern | ((...args: any[]) => any), fn: (...args: any[]) => any): void; - addProcessor(pattern: string | RegExp | Pattern | ((...args: any[]) => any), fn?: (...args: any[]) => any): void { + addProcessor(pattern: string | RegExp | Pattern | ((str: string) => any), fn: (...args: any[]) => any): void; + addProcessor(pattern: string | RegExp | Pattern | ((str: string) => any), fn?: (...args: any[]) => any): void { if (!fn && typeof pattern === 'function') { fn = pattern; pattern = defaultPattern; @@ -100,7 +106,7 @@ class Box extends EventEmitter { }); } - _readDir(base: string, prefix = ''): BlueBirdPromise { + _readDir(base: string, prefix = ''): BlueBirdPromise { const { context: ctx } = this; const results: string[] = []; return readDirWalker(ctx, base, results, this.ignore, prefix) @@ -109,7 +115,7 @@ class Box extends EventEmitter { .map(file => this._processFile(file.type, file.path).return(file.path)); } - _checkFileStatus(path: string) { + _checkFileStatus(path: string): { type: string; path: string } { const { Cache, context: ctx } = this; const src = join(this.base, path); @@ -123,7 +129,7 @@ class Box extends EventEmitter { })); } - process(callback?: NodeJSLikeCallback): BlueBirdPromise { + process(callback?: NodeJSLikeCallback): BlueBirdPromise { const { base, Cache, context: ctx } = this; return stat(base).then(stats => { @@ -131,18 +137,18 @@ class Box extends EventEmitter { // Check existing files in cache const relativeBase = escapeBackslash(base.substring(ctx.base_dir.length)); - const cacheFiles = Cache.filter(item => item._id.startsWith(relativeBase)).map(item => item._id.substring(relativeBase.length)); + const cacheFiles: string[] = Cache.filter(item => item._id.startsWith(relativeBase)).map(item => item._id.substring(relativeBase.length)); // Handle deleted files return this._readDir(base) - .then((files: string[]) => cacheFiles.filter((path: string) => !files.includes(path))) - .map((path: string) => this._processFile(File.TYPE_DELETE, path) as PromiseLike); + .then(files => cacheFiles.filter(path => !files.includes(path))) + .map(path => this._processFile(File.TYPE_DELETE, path)); }).catch(err => { if (err && err.code !== 'ENOENT') throw err; }).asCallback(callback); } - _processFile(type: string, path: string): BlueBirdPromise | BlueBirdPromise { + _processFile(type: string, path: string): BlueBirdPromise { if (this._processingFiles[path]) { return BlueBirdPromise.resolve(); } @@ -160,7 +166,7 @@ class Box extends EventEmitter { const params = processor.pattern.match(path); if (!params) return count; - const file = new File({ + const file: File = new File({ // source is used for filesystem path, keep backslashes on Windows source: join(base, path), // path is used for URL path, replace backslashes on Windows @@ -280,7 +286,7 @@ function readDirWalker(ctx: Hexo, base: string, results: string[], ignore: strin throw err; }), async (path: string) => { const fullPath = join(base, path); - const stats: fs.Stats = await stat(fullPath).catch(err => { + const stats: fs.Stats | null = await stat(fullPath).catch(err => { ctx.log.error({ err }, 'Failed to stat file: %s', fullPath); if (err && err.code === 'ENOENT') return null; throw err; diff --git a/lib/hexo/load_plugins.ts b/lib/hexo/load_plugins.ts index 3c21df4ea5..b4b7b62c44 100644 --- a/lib/hexo/load_plugins.ts +++ b/lib/hexo/load_plugins.ts @@ -10,7 +10,7 @@ export = (ctx: Hexo): Promise => { return loadModules(ctx).then(() => loadScripts(ctx)); }; -function loadModuleList(ctx: Hexo, basedir: string): Promise { +function loadModuleList(ctx: Hexo, basedir: string): Promise> { const packagePath = join(basedir, 'package.json'); // Make sure package.json exists @@ -25,7 +25,7 @@ function loadModuleList(ctx: Hexo, basedir: string): Promise { return basedir === ctx.base_dir ? deps.concat(devDeps) : deps; }); - }).filter(name => { + }).filter((name: string) => { // Ignore plugins whose name is not started with "hexo-" if (!/^hexo-|^@[^/]+\/hexo-/.test(name)) return false; @@ -38,12 +38,12 @@ function loadModuleList(ctx: Hexo, basedir: string): Promise { // Make sure the plugin exists const path = ctx.resolvePlugin(name, basedir); return exists(path); - }).then(modules => { + }).then((modules: string[]) => { return Object.fromEntries(modules.map(name => [name, ctx.resolvePlugin(name, basedir)])); }); } -function loadModules(ctx: Hexo) { +function loadModules(ctx: Hexo): Promise { return Promise.map([ctx.base_dir, ctx.theme_dir], basedir => loadModuleList(ctx, basedir)) .then(([hexoModuleList, themeModuleList]) => { return Object.entries(Object.assign(themeModuleList, hexoModuleList)); @@ -58,7 +58,7 @@ function loadModules(ctx: Hexo) { }); } -function loadScripts(ctx: Hexo) { +function loadScripts(ctx: Hexo): Promise { const baseDirLength = ctx.base_dir.length; return Promise.filter([ @@ -77,6 +77,6 @@ function loadScripts(ctx: Hexo) { })); } -function displayPath(path: string, baseDirLength: number) { +function displayPath(path: string, baseDirLength: number): string { return magenta(path.substring(baseDirLength)); } diff --git a/lib/hexo/locals.ts b/lib/hexo/locals.ts index ef3b51eb27..1a2ea9a237 100644 --- a/lib/hexo/locals.ts +++ b/lib/hexo/locals.ts @@ -1,15 +1,15 @@ import { Cache } from 'hexo-util'; class Locals { - public cache: any; - public getters: any; + public cache: InstanceType; + public getters: Record any>; constructor() { this.cache = new Cache(); this.getters = {}; } - get(name: string) { + get(name: string): any { if (typeof name !== 'string') throw new TypeError('name must be a string!'); return this.cache.apply(name, () => { @@ -47,7 +47,7 @@ class Locals { return this; } - toObject() { + toObject(): Record { const result = {}; const keys = Object.keys(this.getters); diff --git a/lib/hexo/render.ts b/lib/hexo/render.ts index 788201c6e1..e812792c7e 100644 --- a/lib/hexo/render.ts +++ b/lib/hexo/render.ts @@ -13,7 +13,7 @@ const getExtname = (str: string): string => { return ext.startsWith('.') ? ext.slice(1) : ext; }; -const toString = (result: any, options: StoreFunctionData) => { +const toString = (result: any, options: StoreFunctionData): string => { if (!Object.prototype.hasOwnProperty.call(options, 'toString') || typeof result === 'string') return result; if (typeof options.toString === 'function') { diff --git a/lib/theme/index.ts b/lib/theme/index.ts index d28940cbcc..ffe477ed71 100644 --- a/lib/theme/index.ts +++ b/lib/theme/index.ts @@ -7,17 +7,12 @@ import { i18n } from './processors/i18n'; import { source } from './processors/source'; import { view } from './processors/view'; import type Hexo from '../hexo'; -import type { Pattern } from 'hexo-util'; class Theme extends Box { public config: any; public views: Record>; public i18n: I18n; public View: typeof View; - public processors: { - pattern: Pattern; - process: (...args: any[]) => any; - }[]; constructor(ctx: Hexo, options?: any) { super(ctx, ctx.theme_dir, options); From 3e566a57a363c26fd2b88f3ec1556286981b08fe Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Sat, 11 Jan 2025 17:34:26 +0800 Subject: [PATCH 07/10] refactor: refactor type --- lib/extend/console.ts | 3 ++- lib/extend/deployer.ts | 18 ++++++++++++------ lib/extend/migrator.ts | 4 ++-- lib/hexo/default_config.ts | 10 +++++----- lib/plugins/console/deploy.ts | 5 +++-- lib/plugins/console/generate.ts | 21 +++++++++++---------- lib/plugins/console/list/index.ts | 3 ++- lib/plugins/console/list/post.ts | 2 +- lib/plugins/console/migrate.ts | 2 +- lib/plugins/console/new.ts | 3 ++- lib/plugins/console/publish.ts | 3 ++- lib/plugins/console/render.ts | 3 ++- 12 files changed, 45 insertions(+), 32 deletions(-) diff --git a/lib/extend/console.ts b/lib/extend/console.ts index 6e27f6c70b..41181effac 100644 --- a/lib/extend/console.ts +++ b/lib/extend/console.ts @@ -21,7 +21,8 @@ interface Args { [key: string]: string | boolean | string[]; } type AnyFn = (args: Args, callback?: NodeJSLikeCallback) => any; -interface StoreFunction extends AnyFn { +interface StoreFunction { + (args: Args): Promise; desc?: string; options?: Option; } diff --git a/lib/extend/deployer.ts b/lib/extend/deployer.ts index c6def5cfc5..937a83f761 100644 --- a/lib/extend/deployer.ts +++ b/lib/extend/deployer.ts @@ -2,13 +2,10 @@ import Promise from 'bluebird'; import type { NodeJSLikeCallback } from '../types'; interface StoreFunction { - (deployArg: { - type: string; - [key: string]: any - }, callback?: NodeJSLikeCallback) : any; + (deployArg: { type: string; [key: string]: any }): Promise; } interface Store { - [key: string]: StoreFunction + [key: string]: StoreFunction; } /** @@ -29,7 +26,16 @@ class Deployer { return this.store[name]; } - register(name: string, fn: StoreFunction): void { + register( + name: string, + fn: ( + deployArg: { + type: string; + [key: string]: any; + }, + callback?: NodeJSLikeCallback + ) => any + ): void { if (!name) throw new TypeError('name is required'); if (typeof fn !== 'function') throw new TypeError('fn must be a function'); diff --git a/lib/extend/migrator.ts b/lib/extend/migrator.ts index 30fb412da7..1b51772a98 100644 --- a/lib/extend/migrator.ts +++ b/lib/extend/migrator.ts @@ -2,7 +2,7 @@ import Promise from 'bluebird'; import type { NodeJSLikeCallback } from '../types'; interface StoreFunction { - (args: any, callback?: NodeJSLikeCallback): any + (args: any): Promise; } interface Store { @@ -27,7 +27,7 @@ class Migrator { return this.store[name]; } - register(name: string, fn: StoreFunction): void { + register(name: string, fn: (args: any, callback?: NodeJSLikeCallback) => any): void { if (!name) throw new TypeError('name is required'); if (typeof fn !== 'function') throw new TypeError('fn must be a function'); diff --git a/lib/hexo/default_config.ts b/lib/hexo/default_config.ts index 87b40d6e06..6dac40a776 100644 --- a/lib/hexo/default_config.ts +++ b/lib/hexo/default_config.ts @@ -10,7 +10,7 @@ export = { url: 'http://example.com', root: '/', permalink: ':year/:month/:day/:title/', - permalink_defaults: {}, + permalink_defaults: {} as Record, pretty_urls: { trailing_index: true, trailing_html: true @@ -62,8 +62,8 @@ export = { // Category & Tag default_category: 'uncategorized', - category_map: {}, - tag_map: {}, + category_map: {} as Record, + tag_map: {} as Record, // Date / Time format date_format: 'YYYY-MM-DD', time_format: 'HH:mm:ss', @@ -79,10 +79,10 @@ export = { cache: false }, // Deployment - deploy: {}, + deploy: {} as { type: string; [keys: string]: any } | { type: string; [keys: string]: any }[], // ignore files from processing - ignore: [], + ignore: [] as string[], // Category & Tag meta_generator: true diff --git a/lib/plugins/console/deploy.ts b/lib/plugins/console/deploy.ts index 811be33b48..29be2b9229 100644 --- a/lib/plugins/console/deploy.ts +++ b/lib/plugins/console/deploy.ts @@ -1,6 +1,7 @@ import { exists } from 'hexo-fs'; import { underline, magenta } from 'picocolors'; import type Hexo from '../../hexo'; +import type Promise from 'bluebird'; interface DeployArgs { _?: string[] @@ -9,7 +10,7 @@ interface DeployArgs { [key: string]: any } -function deployConsole(this: Hexo, args: DeployArgs) { +function deployConsole(this: Hexo, args: DeployArgs): Promise { let config = this.config.deploy; const deployers = this.extend.deployer.list(); @@ -25,7 +26,7 @@ function deployConsole(this: Hexo, args: DeployArgs) { return; } - let promise; + let promise: Promise; if (args.g || args.generate) { promise = this.call('generate', args); diff --git a/lib/plugins/console/generate.ts b/lib/plugins/console/generate.ts index f6bfcd67a7..27fc2c4140 100644 --- a/lib/plugins/console/generate.ts +++ b/lib/plugins/console/generate.ts @@ -4,9 +4,10 @@ import Promise from 'bluebird'; import prettyHrtime from 'pretty-hrtime'; import { cyan, magenta } from 'picocolors'; import tildify from 'tildify'; -import { PassThrough } from 'stream'; +import { PassThrough, type Readable } from 'stream'; import { createSha1Hash } from 'hexo-util'; import type Hexo from '../../hexo'; +import type Router from '../../hexo/router'; interface GenerateArgs { f?: boolean @@ -22,14 +23,14 @@ interface GenerateArgs { [key: string]: any } -class Generater { +class Generator { public context: Hexo; public force: boolean; public bail: boolean; public concurrency: string; public watch: boolean; public deploy: boolean; - public generatingFiles: Set; + public generatingFiles: Set; public start: [number, number]; public args: GenerateArgs; @@ -44,7 +45,7 @@ class Generater { this.start = process.hrtime(); this.args = args; } - generateFile(path: string) { + generateFile(path: string): Promise { const publicDir = this.context.public_dir; const { generatingFiles } = this; const { route } = this.context; @@ -54,7 +55,7 @@ class Generater { // Lock the file generatingFiles.add(path); - let promise; + let promise: Promise; if (this.force) { promise = this.writeFile(path, true); @@ -71,7 +72,7 @@ class Generater { generatingFiles.delete(path); }); } - writeFile(path: string, force?: boolean): Promise { + writeFile(path: string, force?: boolean): Promise { const { route, log } = this.context; const publicDir = this.context.public_dir; const Cache = this.context.model('Cache'); @@ -79,7 +80,7 @@ class Generater { const buffers = []; const hasher = createSha1Hash(); - const finishedPromise = new Promise((resolve, reject) => { + const finishedPromise = new Promise((resolve, reject) => { dataStream.once('error', reject); dataStream.once('end', resolve); }); @@ -125,7 +126,7 @@ class Generater { throw err; }); } - wrapDataStream(dataStream) { + wrapDataStream(dataStream: ReturnType): Readable { const { log } = this.context; // Pass original stream with all data and errors if (this.bail) { @@ -205,8 +206,8 @@ class Generater { } } -function generateConsole(this: Hexo, args: GenerateArgs = {}) { - const generator = new Generater(this, args); +function generateConsole(this: Hexo, args: GenerateArgs = {}): Promise { + const generator = new Generator(this, args); if (generator.watch) { return generator.execWatch(); diff --git a/lib/plugins/console/list/index.ts b/lib/plugins/console/list/index.ts index f9b3cb4cd5..33a1ac18eb 100644 --- a/lib/plugins/console/list/index.ts +++ b/lib/plugins/console/list/index.ts @@ -5,6 +5,7 @@ import route from './route'; import tag from './tag'; import category from './category'; import type Hexo from '../../../hexo'; +import type Promise from 'bluebird'; interface ListArgs { _: string[] @@ -16,7 +17,7 @@ const store = { const alias = abbrev(Object.keys(store)); -function listConsole(this: Hexo, args: ListArgs) { +function listConsole(this: Hexo, args: ListArgs): Promise { const type = args._.shift(); // Display help message if user didn't input any arguments diff --git a/lib/plugins/console/list/post.ts b/lib/plugins/console/list/post.ts index e213b7577d..05caa1c2a9 100644 --- a/lib/plugins/console/list/post.ts +++ b/lib/plugins/console/list/post.ts @@ -5,7 +5,7 @@ import type Hexo from '../../../hexo'; import type { PostSchema } from '../../../types'; import type Model from 'warehouse/dist/model'; -function mapName(item) { +function mapName(item: any): string { return item.name; } diff --git a/lib/plugins/console/migrate.ts b/lib/plugins/console/migrate.ts index d6b3ad3e47..b9a4791962 100644 --- a/lib/plugins/console/migrate.ts +++ b/lib/plugins/console/migrate.ts @@ -6,7 +6,7 @@ interface MigrateArgs { [key: string]: any } -function migrateConsole(this: Hexo, args: MigrateArgs) { +function migrateConsole(this: Hexo, args: MigrateArgs): Promise { // Display help message if user didn't input any arguments if (!args._.length) { return this.call('help', {_: ['migrate']}); diff --git a/lib/plugins/console/new.ts b/lib/plugins/console/new.ts index 2b48b77b11..79cda98e6b 100644 --- a/lib/plugins/console/new.ts +++ b/lib/plugins/console/new.ts @@ -2,6 +2,7 @@ import tildify from 'tildify'; import { magenta } from 'picocolors'; import { basename } from 'path'; import Hexo from '../../hexo'; +import type Promise from 'bluebird'; const reservedKeys = { _: true, @@ -31,7 +32,7 @@ interface NewArgs { [key: string]: any } -function newConsole(this: Hexo, args: NewArgs) { +function newConsole(this: Hexo, args: NewArgs): Promise { const path = args.p || args.path; let title: string; if (args._.length) { diff --git a/lib/plugins/console/publish.ts b/lib/plugins/console/publish.ts index 38913e8316..b6a60434ca 100644 --- a/lib/plugins/console/publish.ts +++ b/lib/plugins/console/publish.ts @@ -1,6 +1,7 @@ import tildify from 'tildify'; import { magenta } from 'picocolors'; import type Hexo from '../../hexo'; +import type Promise from 'bluebird'; interface PublishArgs { _: string[] @@ -9,7 +10,7 @@ interface PublishArgs { [key: string]: any } -function publishConsole(this: Hexo, args: PublishArgs) { +function publishConsole(this: Hexo, args: PublishArgs): Promise { // Display help message if user didn't input any arguments if (!args._.length) { return this.call('help', {_: ['publish']}); diff --git a/lib/plugins/console/render.ts b/lib/plugins/console/render.ts index 68cb95a710..9247a0d6b3 100644 --- a/lib/plugins/console/render.ts +++ b/lib/plugins/console/render.ts @@ -4,6 +4,7 @@ import prettyHrtime from 'pretty-hrtime'; import { writeFile } from 'hexo-fs'; import { cyan, magenta } from 'picocolors'; import type Hexo from '../../hexo'; +import type Promise from 'bluebird'; interface RenderArgs { _: string[] @@ -14,7 +15,7 @@ interface RenderArgs { [key: string]: any } -function renderConsole(this: Hexo, args: RenderArgs) { +function renderConsole(this: Hexo, args: RenderArgs): Promise { // Display help message if user didn't input any arguments if (!args._.length) { return this.call('help', {_: 'render'}); From ae9475f53a71ae81234d440f4143e92d4946dd0b Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Sat, 11 Jan 2025 21:29:20 +0800 Subject: [PATCH 08/10] refactor: refactor type --- lib/extend/console.ts | 5 +- lib/extend/deployer.ts | 4 +- lib/extend/filter.ts | 7 +-- lib/extend/generator.ts | 13 ++--- lib/extend/injector.ts | 11 ++-- lib/extend/migrator.ts | 5 +- lib/hexo/index.ts | 26 +++++----- lib/plugins/filter/template_locals/i18n.ts | 2 +- lib/plugins/generator/asset.ts | 13 +++-- lib/plugins/generator/page.ts | 9 +++- lib/plugins/generator/post.ts | 9 +++- lib/types.ts | 58 ++++++++++------------ test/scripts/extend/console.ts | 3 +- test/scripts/extend/deployer.ts | 5 +- test/scripts/extend/generator.ts | 2 +- test/scripts/extend/migrator.ts | 5 +- test/scripts/generators/page.ts | 8 +-- test/scripts/generators/post.ts | 10 ++-- test/scripts/hexo/hexo.ts | 6 +-- 19 files changed, 106 insertions(+), 95 deletions(-) diff --git a/lib/extend/console.ts b/lib/extend/console.ts index 41181effac..cb1d61ccb4 100644 --- a/lib/extend/console.ts +++ b/lib/extend/console.ts @@ -1,6 +1,7 @@ import Promise from 'bluebird'; import abbrev from 'abbrev'; import type { NodeJSLikeCallback } from '../types'; +import type Hexo from '../hexo'; type Option = Partial<{ usage: string; @@ -20,9 +21,9 @@ interface Args { _: string[]; [key: string]: string | boolean | string[]; } -type AnyFn = (args: Args, callback?: NodeJSLikeCallback) => any; +type AnyFn = (this: Hexo, args: Args, callback?: NodeJSLikeCallback) => any; interface StoreFunction { - (args: Args): Promise; + (this: Hexo, args: Args): Promise; desc?: string; options?: Option; } diff --git a/lib/extend/deployer.ts b/lib/extend/deployer.ts index 937a83f761..81adb00ed9 100644 --- a/lib/extend/deployer.ts +++ b/lib/extend/deployer.ts @@ -1,8 +1,9 @@ import Promise from 'bluebird'; import type { NodeJSLikeCallback } from '../types'; +import type Hexo from '../hexo'; interface StoreFunction { - (deployArg: { type: string; [key: string]: any }): Promise; + (this: Hexo, deployArg: { type: string; [key: string]: any }): Promise; } interface Store { [key: string]: StoreFunction; @@ -29,6 +30,7 @@ class Deployer { register( name: string, fn: ( + this: Hexo, deployArg: { type: string; [key: string]: any; diff --git a/lib/extend/filter.ts b/lib/extend/filter.ts index a05ef42a49..67b9ebc56d 100644 --- a/lib/extend/filter.ts +++ b/lib/extend/filter.ts @@ -1,4 +1,5 @@ import Promise from 'bluebird'; +import { FilterOptions } from '../types'; const typeAlias = { pre: 'before_post_render', @@ -6,12 +7,6 @@ const typeAlias = { 'after_render:html': '_after_html_render' }; -interface FilterOptions { - context?: any; - args?: any[]; -} - - interface StoreFunction { (data?: any, ...args: any[]): any; priority?: number; diff --git a/lib/extend/generator.ts b/lib/extend/generator.ts index de4add89a2..bb0d238ccc 100644 --- a/lib/extend/generator.ts +++ b/lib/extend/generator.ts @@ -1,22 +1,17 @@ import Promise from 'bluebird'; -import type { NodeJSLikeCallback } from '../types'; +import type { BasicGeneratorReturn, NodeJSLikeCallback, SiteLocals } from '../types'; -interface BaseObj { - path: string; - data?: any; - layout?: string | string[]; -} -type ReturnType = BaseObj | BaseObj[]; +type ReturnType = BasicGeneratorReturn | BasicGeneratorReturn[]; type GeneratorReturnType = ReturnType | Promise; interface GeneratorFunction { - (locals: any, callback?: NodeJSLikeCallback): GeneratorReturnType; + (locals: SiteLocals, callback?: NodeJSLikeCallback): GeneratorReturnType; } type StoreFunctionReturn = Promise; interface StoreFunction { - (locals: any): StoreFunctionReturn; + (locals: SiteLocals): StoreFunctionReturn; } interface Store { diff --git a/lib/extend/injector.ts b/lib/extend/injector.ts index 068c107932..f7b08d3cb5 100644 --- a/lib/extend/injector.ts +++ b/lib/extend/injector.ts @@ -1,10 +1,11 @@ import { Cache } from 'hexo-util'; +import { LocalsType, PageSchema, PostSchema } from '../types'; type Entry = 'head_begin' | 'head_end' | 'body_begin' | 'body_end'; type Store = { [key in Entry]: { - [key: string]: Set; + [key: string]: Set; }; }; @@ -14,7 +15,7 @@ type Store = { */ class Injector { public store: Store; - public cache: any; + public cache: InstanceType; public page: any; constructor() { @@ -42,8 +43,8 @@ class Injector { return arr.join(''); } - getSize(entry: Entry) { - return this.cache.apply(`${entry}-size`, Object.keys(this.store[entry]).length); + getSize(entry: Entry): number { + return this.cache.apply(`${entry}-size`, Object.keys(this.store[entry]).length) as number; } register(entry: Entry, value: string | (() => string), to = 'default'): void { @@ -77,7 +78,7 @@ class Injector { if (!content.length) return ''; return '' + content + ''; - }); + }) as string; // avoid unnecessary replace() for better performance if (!code.length) return input; diff --git a/lib/extend/migrator.ts b/lib/extend/migrator.ts index 1b51772a98..0f24a7339f 100644 --- a/lib/extend/migrator.ts +++ b/lib/extend/migrator.ts @@ -1,8 +1,9 @@ import Promise from 'bluebird'; import type { NodeJSLikeCallback } from '../types'; +import type Hexo from '../hexo'; interface StoreFunction { - (args: any): Promise; + (this: Hexo, args: any): Promise; } interface Store { @@ -27,7 +28,7 @@ class Migrator { return this.store[name]; } - register(name: string, fn: (args: any, callback?: NodeJSLikeCallback) => any): void { + register(name: string, fn: (this: Hexo, args: any, callback?: NodeJSLikeCallback) => any): void { if (!name) throw new TypeError('name is required'); if (typeof fn !== 'function') throw new TypeError('fn must be a function'); diff --git a/lib/hexo/index.ts b/lib/hexo/index.ts index f7f5a21a49..017a97a590 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 { AssetGenerator, LocalsType, NodeJSLikeCallback, NormalPageGenerator, NormalPostGenerator, PageGenerator, PostGenerator, SiteLocals } from '../types'; +import type { BasicGeneratorReturn, FilterOptions, LocalsType, NodeJSLikeCallback, SiteLocals } from '../types'; import type { AddSchemaTypeOptions } from 'warehouse/dist/types'; import type Schema from 'warehouse/dist/schema'; @@ -60,11 +60,11 @@ const mergeCtxThemeConfig = (ctx: Hexo) => { }; // eslint-disable-next-line no-use-before-define -const createLoadThemeRoute = function(generatorResult: NormalPageGenerator | NormalPostGenerator, locals: LocalsType, ctx: Hexo) { +const createLoadThemeRoute = function(generatorResult: BasicGeneratorReturn, locals: LocalsType, ctx: Hexo) { const { log, theme } = ctx; const { path, cache: useCache } = locals; - const layout: string[] = [...new Set(castArray(generatorResult.layout))]; + const layout = [...new Set(castArray(generatorResult.layout))]; const layoutLength = layout.length; // always use cache in fragment_cache @@ -606,7 +606,7 @@ class Hexo extends EventEmitter { const localsObj = this.locals.toObject() as SiteLocals; class Locals { - page: NormalPageGenerator | NormalPostGenerator; + page: any; path: string; url: string; config: any; @@ -617,7 +617,7 @@ class Hexo extends EventEmitter { site: SiteLocals; cache?: boolean; - constructor(path: string, locals: NormalPageGenerator | NormalPostGenerator) { + constructor(path: string, locals: any) { this.page = { ...locals }; if (this.page.path == null) this.page.path = path; this.path = path; @@ -634,7 +634,7 @@ class Hexo extends EventEmitter { return Locals; } - _runGenerators(): Promise<(AssetGenerator | PostGenerator | PageGenerator)[]> { + _runGenerators(): Promise { this.locals.invalidate(); const siteLocals = this.locals.toObject() as SiteLocals; const generators = this.extend.generator.list(); @@ -651,19 +651,17 @@ class Hexo extends EventEmitter { }, []); } - _routerRefresh(runningGenerators: Promise<(AssetGenerator | PostGenerator | PageGenerator)[]>, useCache: boolean): Promise { + _routerRefresh(runningGenerators: Promise, useCache: boolean): Promise { const { route } = this; const routeList = route.list(); const Locals = this._generateLocals(); Locals.prototype.cache = useCache; - return runningGenerators.map((generatorResult: AssetGenerator | PostGenerator | PageGenerator) => { + return runningGenerators.map(generatorResult => { 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-expect-error const { data, layout } = generatorResult; if (!layout) { @@ -671,8 +669,8 @@ class Hexo extends EventEmitter { return path; } - 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)); }) + return this.execFilter('template_locals', new Locals(path, data), { context: this }) + .then((locals: LocalsType) => { route.set(path, createLoadThemeRoute(generatorResult, locals, this)); }) .thenReturn(path); }).then(newRouteList => { // Remove old routes @@ -727,11 +725,11 @@ class Hexo extends EventEmitter { }); } - execFilter(type: string, data: any, options?) { + execFilter(type: string, data: any, options?: FilterOptions) { return this.extend.filter.exec(type, data, options); } - execFilterSync(type: string, data: any, options?) { + execFilterSync(type: string, data: any, options?: FilterOptions) { return this.extend.filter.execSync(type, data, options); } } diff --git a/lib/plugins/filter/template_locals/i18n.ts b/lib/plugins/filter/template_locals/i18n.ts index 7411a94b23..9a9adb5185 100644 --- a/lib/plugins/filter/template_locals/i18n.ts +++ b/lib/plugins/filter/template_locals/i18n.ts @@ -27,7 +27,7 @@ function i18nLocalsFilter(this: Hexo, locals: LocalsType): void { page.lang = lang; page.canonical_path = page.canonical_path || locals.path; - const languages = [...new Set([].concat(lang, i18nConfigLanguages, i18nLanguages).filter(Boolean))]; + const languages = [...new Set([].concat(lang, i18nConfigLanguages, i18nLanguages).filter(Boolean))]; locals.__ = i18n.__(languages); locals._p = i18n._p(languages); diff --git a/lib/plugins/generator/asset.ts b/lib/plugins/generator/asset.ts index 70fde55d8c..8dc445f5f5 100644 --- a/lib/plugins/generator/asset.ts +++ b/lib/plugins/generator/asset.ts @@ -4,21 +4,28 @@ import Promise from 'bluebird'; import { extname } from 'path'; import { magenta } from 'picocolors'; import type Hexo from '../../hexo'; -import type { AssetGenerator, AssetSchema } from '../../types'; +import type { AssetSchema, BasicGeneratorReturn } from '../../types'; import type Document from 'warehouse/dist/document'; -interface Data { +interface AssetData { modified: boolean; data?: () => any; } +interface AssetGenerator extends BasicGeneratorReturn { + data: { + modified: boolean; + data?: () => any; + } +} + const process = (name: string, ctx: Hexo) => { return Promise.filter(ctx.model(name).toArray(), (asset: Document) => exists(asset.source).tap(exist => { if (!exist) return asset.remove(); })).map((asset: Document) => { const { source } = asset; let { path } = asset; - const data: Data = { + const data: AssetData = { modified: asset.modified }; diff --git a/lib/plugins/generator/page.ts b/lib/plugins/generator/page.ts index da2cf08c8b..25de5a13c3 100644 --- a/lib/plugins/generator/page.ts +++ b/lib/plugins/generator/page.ts @@ -1,4 +1,11 @@ -import type { PageGenerator, PageSchema, SiteLocals } from '../../types'; +import type { BasicGeneratorReturn, PageSchema, SiteLocals } from '../../types'; + +type SimplePageGenerator = Omit & { data: string }; +interface NormalPageGenerator extends BasicGeneratorReturn { + layout: string[]; + data: PageSchema; +} +type PageGenerator = SimplePageGenerator | NormalPageGenerator; function pageGenerator(locals: SiteLocals): PageGenerator[] { return locals.pages.map((page: PageSchema) => { diff --git a/lib/plugins/generator/post.ts b/lib/plugins/generator/post.ts index bf832872ca..281ea19849 100644 --- a/lib/plugins/generator/post.ts +++ b/lib/plugins/generator/post.ts @@ -1,6 +1,13 @@ -import type { PostGenerator, PostSchema, SiteLocals } from '../../types'; +import type { BasicGeneratorReturn, PostSchema, SiteLocals } from '../../types'; import type Document from 'warehouse/dist/document'; +type SimplePostGenerator = Omit & { data: string }; +interface NormalPostGenerator extends BasicGeneratorReturn { + data: PostSchema | Document; + layout: string[]; +} +type PostGenerator = SimplePostGenerator | NormalPostGenerator; + function postGenerator(locals: SiteLocals): PostGenerator[] { const posts = locals.posts.sort('-date').toArray(); const { length } = posts; diff --git a/lib/types.ts b/lib/types.ts index e454ab95b1..f7ee31c754 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,5 +1,6 @@ import moment from 'moment'; import type default_config from './hexo/default_config'; +import type i18n from 'hexo-i18n'; import type Query from 'warehouse/dist/query'; import type css from './plugins/helper/css'; import type { date, date_xml, time, full_date, relative_date, time_tag, moment as _moment } from './plugins/helper/date'; @@ -30,8 +31,6 @@ import type search_form from './plugins/helper/search_form'; import type tag_cloud from './plugins/helper/tagcloud'; import type toc from './plugins/helper/toc'; import type url_for from './plugins/helper/url_for'; -import type Model from 'warehouse/dist/model'; -import type Document from 'warehouse/dist/document'; export type NodeJSLikeCallback = (err: E, result?: R) => void @@ -178,6 +177,7 @@ export interface CacheSchema { } export interface LocalsType { + // original properties from Locals class page: PostSchema | PageSchema; path: string; url: string; @@ -188,6 +188,11 @@ export interface LocalsType { view_dir: string; site: any; cache?: boolean; + + // i18n properties from i18nLocalsFilter + __: ReturnType; + _p: ReturnType; + body?: string; filename?: string; css: typeof css; @@ -242,46 +247,37 @@ export interface LocalsType { truncate: typeof truncate; url_for: typeof url_for; word_wrap: typeof word_wrap; - __?: (key: string) => string; - _p?: (key: string, options?: any) => string; } // Generator return types -export interface AssetGenerator { - path: string; - data: { - modified: boolean; - data?: () => any; - } -} +export interface BasicGeneratorReturn { -export type SimplePostGenerator = { - path: string; - data: string; -} -export type NormalPostGenerator = { + /** + * Path not including the prefixing `/`. + */ path: string; - layout: string[]; - data: PostSchema | Document; -} -export type PostGenerator = SimplePostGenerator | NormalPostGenerator; + /** + * Data + */ + data?: any; -export type SimplePageGenerator = { - path: string; - data: string; -} -export type NormalPageGenerator = { - path: string; - layout: string[]; - data: PageSchema; + /** + * Layout. Specify the layouts for rendering. The value can be a string or an array. + * If it’s ignored then the route will return `data` directly. + */ + layout?: string | string[]; } -export type PageGenerator = SimplePageGenerator | NormalPageGenerator; export interface SiteLocals { posts: Query; // _Query pages: Query; // _Query - categories: Model; // _Model - tags: Model; // _Model + categories: Query; // _Query + tags: Query; // _Query data: any; } + +export interface FilterOptions { + context?: any; + args?: any[]; +} diff --git a/test/scripts/extend/console.ts b/test/scripts/extend/console.ts index 2633f18575..adfedb6e9f 100644 --- a/test/scripts/extend/console.ts +++ b/test/scripts/extend/console.ts @@ -3,6 +3,7 @@ import chai from 'chai'; const should = chai.should(); describe('Console', () => { + const ctx = {}; it('register()', () => { const c = new Console(); @@ -69,7 +70,7 @@ describe('Console', () => { callback && callback(null, 'foo'); }); - c.get('test')({ + c.get('test').call(ctx, { _: [], foo: 'bar' }).then(result => { diff --git a/test/scripts/extend/deployer.ts b/test/scripts/extend/deployer.ts index 100f929455..968239b644 100644 --- a/test/scripts/extend/deployer.ts +++ b/test/scripts/extend/deployer.ts @@ -3,6 +3,7 @@ import chai from 'chai'; const should = chai.should(); describe('Deployer', () => { + const ctx = {}; it('register()', () => { const d = new Deployer(); @@ -28,7 +29,7 @@ describe('Deployer', () => { callback && callback(null, 'foo'); }); - d.get('test')({ + d.get('test').call(ctx, { type: '', foo: 'bar' }).then(result => { @@ -44,7 +45,7 @@ describe('Deployer', () => { return 'foo'; }); - d.get('test')({ + d.get('test').call(ctx, { type: '', foo: 'bar' }).then(result => { diff --git a/test/scripts/extend/generator.ts b/test/scripts/extend/generator.ts index f227e7fe0d..9777fa92ea 100644 --- a/test/scripts/extend/generator.ts +++ b/test/scripts/extend/generator.ts @@ -29,7 +29,7 @@ describe('Generator', () => { return []; }); - const result = await g.get('test')({}); + const result = await g.get('test')({} as any); result.should.eql('foo'); }); diff --git a/test/scripts/extend/migrator.ts b/test/scripts/extend/migrator.ts index c1a7ccb73c..5cc9d344c5 100644 --- a/test/scripts/extend/migrator.ts +++ b/test/scripts/extend/migrator.ts @@ -3,6 +3,7 @@ import chai from 'chai'; const should = chai.should(); describe('Migrator', () => { + const ctx = {}; it('register()', () => { const d = new Migrator(); @@ -28,7 +29,7 @@ describe('Migrator', () => { callback && callback(null, 'foo'); }); - d.get('test')({ + d.get('test').call(ctx, { foo: 'bar' }).then(result => { result.should.eql('foo'); @@ -43,7 +44,7 @@ describe('Migrator', () => { return 'foo'; }); - const result = await d.get('test')({ + const result = await d.get('test').call(ctx, { foo: 'bar' }); diff --git a/test/scripts/generators/page.ts b/test/scripts/generators/page.ts index 16e2911b04..958f20d79a 100644 --- a/test/scripts/generators/page.ts +++ b/test/scripts/generators/page.ts @@ -1,8 +1,8 @@ import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import pageGenerator from '../../../lib/plugins/generator/page'; -import { NormalPostGenerator } from '../../../lib/types'; import chai from 'chai'; +import { BasicGeneratorReturn } from '../../../lib/types'; const should = chai.should(); type PageGeneratorParams = Parameters; type PageGeneratorReturn = ReturnType; @@ -42,8 +42,8 @@ describe('page', () => { path: 'bar', layout: 'photo' }); - const data = await generator(locals()) as NormalPostGenerator[]; - data[0].layout.should.eql(['photo', 'page', 'post', 'index']); + const data = await generator(locals()) as BasicGeneratorReturn[]; + data[0].layout!.should.eql(['photo', 'page', 'post', 'index']); page.remove(); }); @@ -55,7 +55,7 @@ describe('page', () => { path: 'bar', layout }); - const data = await generator(locals()) as NormalPostGenerator[]; + const data = await generator(locals()) as BasicGeneratorReturn[]; should.not.exist(data[0].layout); page.remove(); diff --git a/test/scripts/generators/post.ts b/test/scripts/generators/post.ts index 59ed7ca238..93990d69f6 100644 --- a/test/scripts/generators/post.ts +++ b/test/scripts/generators/post.ts @@ -1,7 +1,7 @@ import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import postGenerator from '../../../lib/plugins/generator/post'; -import { NormalPostGenerator } from '../../../lib/types'; +import { BasicGeneratorReturn } from '../../../lib/types'; import chai from 'chai'; const should = chai.should(); type PostGeneratorParams = Parameters; @@ -46,8 +46,8 @@ describe('post', () => { slug: 'bar', layout: 'photo' }); - const data = await generator(locals()) as NormalPostGenerator[]; - data[0].layout.should.eql(['photo', 'post', 'page', 'index']); + const data = await generator(locals()) as BasicGeneratorReturn[]; + data[0].layout!.should.eql(['photo', 'post', 'page', 'index']); post.remove(); }); @@ -58,7 +58,7 @@ describe('post', () => { slug: 'bar', layout: false }); - const data = await generator(locals()) as NormalPostGenerator[]; + const data = await generator(locals()) as BasicGeneratorReturn[]; should.not.exist(data[0].layout); post.remove(); @@ -70,7 +70,7 @@ describe('post', () => { {source: 'bar', slug: 'bar', date: 1e8 + 1}, {source: 'baz', slug: 'baz', date: 1e8 - 1} ]); - const data = await generator(locals()) as NormalPostGenerator[]; + const data = await generator(locals()) as BasicGeneratorReturn[]; should.not.exist(data[0].data.prev); data[0].data.next!._id!.should.eq(posts[0]._id); data[1].data.prev!._id!.should.eq(posts[1]._id); diff --git a/test/scripts/hexo/hexo.ts b/test/scripts/hexo/hexo.ts index 50b5b2a287..e2a0cfcd9f 100644 --- a/test/scripts/hexo/hexo.ts +++ b/test/scripts/hexo/hexo.ts @@ -167,7 +167,6 @@ describe('Hexo', () => { themeConfig.a.b.should.eql(3); const Locals = hexo._generateLocals(); - // @ts-expect-error const { theme: themeLocals } = new Locals('', {path: '', layout: [], data: {}}); themeLocals.a.should.have.own.property('c'); @@ -187,7 +186,6 @@ describe('Hexo', () => { themeConfig.c.should.eql(3); const Locals = hexo._generateLocals(); - // @ts-expect-error const { theme: themeLocals } = new Locals('', {path: '', layout: [], data: {}}); themeLocals.should.have.own.property('c'); @@ -392,7 +390,7 @@ describe('Hexo', () => { it('_generate()', async () => { // object - hexo.extend.generator.register('test_obj', locals => { + hexo.extend.generator.register('test_obj', (locals: any) => { locals.test.should.eql('foo'); return { @@ -402,7 +400,7 @@ describe('Hexo', () => { }); // array - hexo.extend.generator.register('test_arr', locals => { + hexo.extend.generator.register('test_arr', (locals: any) => { locals.test.should.eql('foo'); return [ From 74ab0906de91b8e189b63a23a6a02dc195218ab2 Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Sun, 12 Jan 2025 15:18:07 +0800 Subject: [PATCH 09/10] refactor: refactor types --- lib/extend/renderer.ts | 34 +++--- lib/hexo/index.ts | 4 +- .../filter/before_generate/render_post.ts | 3 +- lib/theme/view.ts | 6 +- lib/types.ts | 107 +++++++++++++----- test/scripts/extend/renderer.ts | 2 +- 6 files changed, 106 insertions(+), 50 deletions(-) diff --git a/lib/extend/renderer.ts b/lib/extend/renderer.ts index 18413f3e14..9c8b156582 100644 --- a/lib/extend/renderer.ts +++ b/lib/extend/renderer.ts @@ -18,29 +18,37 @@ export interface StoreFunctionData { } export interface StoreSyncFunction { - [x: string]: any; ( data: StoreFunctionData, - options: object, - // callback?: NodeJSLikeCallback + options?: object ): any; output?: string; - compile?: (local: object) => any; + compile?: (data: StoreFunctionData) => (local: any) => any; + disableNunjucks?: boolean; + [key: string]: any; } + export interface StoreFunction { ( data: StoreFunctionData, - options: object, - callback?: NodeJSLikeCallback + options?: object ): Promise; + output?: string; + compile?: (data: StoreFunctionData) => (local: any) => any; + disableNunjucks?: boolean; + [key: string]: any; +} + +interface StoreFunctionWithCallback { ( data: StoreFunctionData, options: object, - callback: NodeJSLikeCallback - ): void; + callback?: NodeJSLikeCallback + ): Promise; output?: string; - compile?: (local: object) => any; + compile?: (data: StoreFunctionData) => (local: any) => any; disableNunjucks?: boolean; + [key: string]: any; } interface SyncStore { @@ -85,11 +93,11 @@ class Renderer { return renderer ? renderer.output : ''; } - register(name: string, output: string, fn: StoreFunction): void; - register(name: string, output: string, fn: StoreFunction, sync: false): void; + register(name: string, output: string, fn: StoreFunctionWithCallback): void; + register(name: string, output: string, fn: StoreFunctionWithCallback, sync: false): void; register(name: string, output: string, fn: StoreSyncFunction, sync: true): void; - register(name: string, output: string, fn: StoreFunction | StoreSyncFunction, sync: boolean): void; - register(name: string, output: string, fn: StoreFunction | StoreSyncFunction, sync?: boolean) { + register(name: string, output: string, fn: StoreFunctionWithCallback | StoreSyncFunction, sync: boolean): void; + register(name: string, output: string, fn: StoreFunctionWithCallback | StoreSyncFunction, sync?: boolean) { if (!name) throw new TypeError('name is required'); if (!output) throw new TypeError('output is required'); if (typeof fn !== 'function') throw new TypeError('fn must be a function'); diff --git a/lib/hexo/index.ts b/lib/hexo/index.ts index 017a97a590..2b2962e59b 100644 --- a/lib/hexo/index.ts +++ b/lib/hexo/index.ts @@ -609,10 +609,10 @@ class Hexo extends EventEmitter { page: any; path: string; url: string; - config: any; + config: Config; theme: any; layout: string; - env: any; + env: Env; view_dir: string; site: SiteLocals; cache?: boolean; diff --git a/lib/plugins/filter/before_generate/render_post.ts b/lib/plugins/filter/before_generate/render_post.ts index 0a6cbe78d8..9c2d640066 100644 --- a/lib/plugins/filter/before_generate/render_post.ts +++ b/lib/plugins/filter/before_generate/render_post.ts @@ -1,8 +1,9 @@ import Promise from 'bluebird'; import type Hexo from '../../../hexo'; +import type Model from 'warehouse/dist/model'; function renderPostFilter(this: Hexo): Promise<[any[], any[]]> { - const renderPosts = model => { + const renderPosts = (model: Model) => { const posts = model.toArray().filter(post => post.content == null); return Promise.map(posts, (post: any) => { diff --git a/lib/theme/view.ts b/lib/theme/view.ts index 7c7887a3f3..e281a95961 100644 --- a/lib/theme/view.ts +++ b/lib/theme/view.ts @@ -30,8 +30,8 @@ class View { public source: string; public _theme: Theme; public data: any; - public _compiled: any; - public _compiledSync: any; + public _compiled: (locals: any) => Promise; + public _compiledSync: (locals: any) => any; public _helper: Helper; public _render: Render; @@ -131,7 +131,7 @@ class View { text: this.data._content }; - function buildFilterArguments(result: any): [string, any, any] { + function buildFilterArguments(result: any): [string, any, { context: any, args: any[] }] { const output = render.getOutput(ext) || ext; return [ `after_render:${output}`, diff --git a/lib/types.ts b/lib/types.ts index f7ee31c754..66b9e5827d 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -176,25 +176,100 @@ export interface CacheSchema { modified: number; } +// Generator return types +export interface BasicGeneratorReturn { + + /** + * Path not including the prefixing `/`. + */ + path: string; + + /** + * Data + */ + data?: any; + + /** + * Layout. Specify the layouts for rendering. The value can be a string or an array. + * If it’s ignored then the route will return `data` directly. + */ + layout?: string | string[]; +} + +export interface SiteLocals { + + /** + * All posts + */ + posts: Query; + + /** + * All pages + */ + pages: Query; + + /** + * All categories + */ + categories: Query; + + /** + * All tags + */ + tags: Query; + data: any; +} + export interface LocalsType { // original properties from Locals class - page: PostSchema | PageSchema; + /** + * Page specific information and custom variables set in front-matter. + */ + page: any; + + /** + * Path of current page + */ path: string; + + /** + * Full URL of current page + */ url: string; + + /** + * Site configuration. + */ config: typeof default_config; + + /** + * Theme configuration. Inherits from site configuration. + */ theme: any; layout: string | boolean; + + /** + * Environment variables + */ env: any; view_dir: string; - site: any; + + /** + * Sitewide information. + */ + site: SiteLocals; cache?: boolean; // i18n properties from i18nLocalsFilter __: ReturnType; _p: ReturnType; + // result after renderer.compile body?: string; + // from _buildLocals filename?: string; + + // helper functions from _bindHelpers css: typeof css; date: typeof date; date_xml: typeof date_xml; @@ -249,34 +324,6 @@ export interface LocalsType { word_wrap: typeof word_wrap; } -// Generator return types -export interface BasicGeneratorReturn { - - /** - * Path not including the prefixing `/`. - */ - path: string; - - /** - * Data - */ - data?: any; - - /** - * Layout. Specify the layouts for rendering. The value can be a string or an array. - * If it’s ignored then the route will return `data` directly. - */ - layout?: string | string[]; -} - -export interface SiteLocals { - posts: Query; // _Query - pages: Query; // _Query - categories: Query; // _Query - tags: Query; // _Query - data: any; -} - export interface FilterOptions { context?: any; args?: any[]; diff --git a/test/scripts/extend/renderer.ts b/test/scripts/extend/renderer.ts index 4432ee2aa9..2faa3a32c5 100644 --- a/test/scripts/extend/renderer.ts +++ b/test/scripts/extend/renderer.ts @@ -62,7 +62,7 @@ describe('Renderer', () => { } renderer.compile = data => { - // + return () => {}; }; r.register('swig', 'html', renderer); From ca634e5dc3c8102e6a4a3cb156cd011fc335388d Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Sun, 12 Jan 2025 18:33:06 +0800 Subject: [PATCH 10/10] refactor: refactor types --- lib/extend/generator.ts | 4 +- lib/extend/renderer.ts | 2 +- lib/hexo/index.ts | 8 +- lib/hexo/post.ts | 35 ++-- lib/hexo/router.ts | 1 - lib/plugins/generator/asset.ts | 4 +- lib/plugins/generator/page.ts | 6 +- lib/plugins/generator/post.ts | 6 +- lib/plugins/processor/asset.ts | 15 +- lib/plugins/processor/common.ts | 5 +- lib/plugins/processor/post.ts | 29 ++-- lib/types.ts | 287 ++++++++++++++++++++++++++------ test/scripts/generators/page.ts | 6 +- test/scripts/generators/post.ts | 8 +- 14 files changed, 304 insertions(+), 112 deletions(-) diff --git a/lib/extend/generator.ts b/lib/extend/generator.ts index bb0d238ccc..feb444ac7b 100644 --- a/lib/extend/generator.ts +++ b/lib/extend/generator.ts @@ -1,7 +1,7 @@ import Promise from 'bluebird'; -import type { BasicGeneratorReturn, NodeJSLikeCallback, SiteLocals } from '../types'; +import type { BaseGeneratorReturn, NodeJSLikeCallback, SiteLocals } from '../types'; -type ReturnType = BasicGeneratorReturn | BasicGeneratorReturn[]; +type ReturnType = BaseGeneratorReturn | BaseGeneratorReturn[]; type GeneratorReturnType = ReturnType | Promise; interface GeneratorFunction { diff --git a/lib/extend/renderer.ts b/lib/extend/renderer.ts index 9c8b156582..6ed620fff5 100644 --- a/lib/extend/renderer.ts +++ b/lib/extend/renderer.ts @@ -14,7 +14,7 @@ export interface StoreFunctionData { text?: string; engine?: string; toString?: any; - onRenderEnd?: (...args: any[]) => any; + onRenderEnd?: (data: string) => any; } export interface StoreSyncFunction { diff --git a/lib/hexo/index.ts b/lib/hexo/index.ts index 2b2962e59b..6a8f695ad1 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 { BasicGeneratorReturn, FilterOptions, LocalsType, NodeJSLikeCallback, SiteLocals } from '../types'; +import type { BaseGeneratorReturn, FilterOptions, LocalsType, NodeJSLikeCallback, SiteLocals } from '../types'; import type { AddSchemaTypeOptions } from 'warehouse/dist/types'; import type Schema from 'warehouse/dist/schema'; @@ -60,7 +60,7 @@ const mergeCtxThemeConfig = (ctx: Hexo) => { }; // eslint-disable-next-line no-use-before-define -const createLoadThemeRoute = function(generatorResult: BasicGeneratorReturn, locals: LocalsType, ctx: Hexo) { +const createLoadThemeRoute = function(generatorResult: BaseGeneratorReturn, locals: LocalsType, ctx: Hexo) { const { log, theme } = ctx; const { path, cache: useCache } = locals; @@ -634,7 +634,7 @@ class Hexo extends EventEmitter { return Locals; } - _runGenerators(): Promise { + _runGenerators(): Promise { this.locals.invalidate(); const siteLocals = this.locals.toObject() as SiteLocals; const generators = this.extend.generator.list(); @@ -651,7 +651,7 @@ class Hexo extends EventEmitter { }, []); } - _routerRefresh(runningGenerators: Promise, useCache: boolean): Promise { + _routerRefresh(runningGenerators: Promise, useCache: boolean): Promise { const { route } = this; const routeList = route.list(); const Locals = this._generateLocals(); diff --git a/lib/hexo/post.ts b/lib/hexo/post.ts index 2efeae4dca..d05a37af2d 100644 --- a/lib/hexo/post.ts +++ b/lib/hexo/post.ts @@ -31,19 +31,19 @@ const isNonWhiteSpaceChar = (char: string) => char !== '\r' && char !== ' '; class PostRenderEscape { - public stored: any[]; + public stored: string[]; public length: number; constructor() { this.stored = []; } - static escapeContent(cache: any[], flag: string, str: string) { + static escapeContent(cache: string[], flag: string, str: string) { return ``; } - static restoreContent(cache: any[]) { - return (_, index) => { + static restoreContent(cache: string[]) { + return (_: string, index: number) => { assert(cache[index]); const value = cache[index]; cache[index] = null; @@ -192,7 +192,7 @@ class PostRenderEscape { } } -const prepareFrontMatter = (data: any, jsonMode: boolean) => { +const prepareFrontMatter = (data: any, jsonMode: boolean): Record => { for (const [key, item] of Object.entries(data)) { if (moment.isMoment(item)) { data[key] = item.utc().format('YYYY-MM-DD HH:mm:ss'); @@ -226,8 +226,8 @@ const createAssetFolder = (path: string, assetFolder: boolean) => { }; interface Result { - path?: string; - content?: string; + path: string; + content: string; } interface PostData { @@ -235,6 +235,7 @@ interface PostData { layout?: string; slug?: string | number; path?: string; + date?: moment.Moment; [prop: string]: any; } @@ -245,9 +246,9 @@ class Post { this.context = context; } - create(data: PostData, callback?: NodeJSLikeCallback); - create(data: PostData, replace: boolean, callback?: NodeJSLikeCallback); - create(data: PostData, replace: boolean | (NodeJSLikeCallback), callback?: NodeJSLikeCallback) { + create(data: PostData, callback?: NodeJSLikeCallback): Promise; + create(data: PostData, replace: boolean, callback?: NodeJSLikeCallback): Promise; + create(data: PostData, replace: boolean | (NodeJSLikeCallback), callback?: NodeJSLikeCallback): Promise { if (!callback && typeof replace === 'function') { callback = replace; replace = false; @@ -267,7 +268,7 @@ class Post { context: ctx }), this._renderScaffold(data) - ]).spread((path, content) => { + ]).spread((path: string, content: string) => { const result = { path, content }; return Promise.all([ @@ -293,7 +294,7 @@ class Post { _renderScaffold(data: PostData) { const { tag } = this.context.extend; - let splitted; + let splitted: ReturnType; return this._getScaffold(data.layout).then(scaffold => { splitted = yfmSplit(scaffold); @@ -329,10 +330,10 @@ class Post { }); } - publish(data: PostData, replace?: boolean); - publish(data: PostData, callback?: NodeJSLikeCallback); - publish(data: PostData, replace: boolean, callback?: NodeJSLikeCallback); - publish(data: PostData, replace?: boolean | NodeJSLikeCallback, callback?: NodeJSLikeCallback) { + publish(data: PostData, replace?: boolean): Promise; + publish(data: PostData, callback?: NodeJSLikeCallback): Promise; + publish(data: PostData, replace: boolean, callback?: NodeJSLikeCallback): Promise; + publish(data: PostData, replace?: boolean | NodeJSLikeCallback, callback?: NodeJSLikeCallback): Promise { if (!callback && typeof replace === 'function') { callback = replace; replace = false; @@ -347,7 +348,7 @@ class Post { data.slug = slug; const regex = new RegExp(`^${escapeRegExp(slug)}(?:[^\\/\\\\]+)`); let src = ''; - const result: Result = {}; + const result: Result = {} as any; data.layout = (data.layout || config.default_layout).toLowerCase(); diff --git a/lib/hexo/router.ts b/lib/hexo/router.ts index 91d89d51f4..4f643509c7 100644 --- a/lib/hexo/router.ts +++ b/lib/hexo/router.ts @@ -105,7 +105,6 @@ class Router extends EventEmitter { public routes: { [key: string]: Data | null; }; - public emit: any; constructor() { super(); diff --git a/lib/plugins/generator/asset.ts b/lib/plugins/generator/asset.ts index 8dc445f5f5..137f76fa2e 100644 --- a/lib/plugins/generator/asset.ts +++ b/lib/plugins/generator/asset.ts @@ -4,7 +4,7 @@ import Promise from 'bluebird'; import { extname } from 'path'; import { magenta } from 'picocolors'; import type Hexo from '../../hexo'; -import type { AssetSchema, BasicGeneratorReturn } from '../../types'; +import type { AssetSchema, BaseGeneratorReturn } from '../../types'; import type Document from 'warehouse/dist/document'; interface AssetData { @@ -12,7 +12,7 @@ interface AssetData { data?: () => any; } -interface AssetGenerator extends BasicGeneratorReturn { +interface AssetGenerator extends BaseGeneratorReturn { data: { modified: boolean; data?: () => any; diff --git a/lib/plugins/generator/page.ts b/lib/plugins/generator/page.ts index 25de5a13c3..269d28dfc0 100644 --- a/lib/plugins/generator/page.ts +++ b/lib/plugins/generator/page.ts @@ -1,7 +1,7 @@ -import type { BasicGeneratorReturn, PageSchema, SiteLocals } from '../../types'; +import type { BaseGeneratorReturn, PageSchema, SiteLocals } from '../../types'; -type SimplePageGenerator = Omit & { data: string }; -interface NormalPageGenerator extends BasicGeneratorReturn { +type SimplePageGenerator = Omit & { data: string }; +interface NormalPageGenerator extends BaseGeneratorReturn { layout: string[]; data: PageSchema; } diff --git a/lib/plugins/generator/post.ts b/lib/plugins/generator/post.ts index 281ea19849..99acdacaf5 100644 --- a/lib/plugins/generator/post.ts +++ b/lib/plugins/generator/post.ts @@ -1,8 +1,8 @@ -import type { BasicGeneratorReturn, PostSchema, SiteLocals } from '../../types'; +import type { BaseGeneratorReturn, PostSchema, SiteLocals } from '../../types'; import type Document from 'warehouse/dist/document'; -type SimplePostGenerator = Omit & { data: string }; -interface NormalPostGenerator extends BasicGeneratorReturn { +type SimplePostGenerator = Omit & { data: string }; +interface NormalPostGenerator extends BaseGeneratorReturn { data: PostSchema | Document; layout: string[]; } diff --git a/lib/plugins/processor/asset.ts b/lib/plugins/processor/asset.ts index c56ff62052..e538bacffd 100644 --- a/lib/plugins/processor/asset.ts +++ b/lib/plugins/processor/asset.ts @@ -7,6 +7,7 @@ import { magenta } from 'picocolors'; import type { _File } from '../../box'; import type Hexo from '../../hexo'; import type { Stats } from 'fs'; +import { PageSchema } from '../../types'; export = (ctx: Hexo) => { return { @@ -52,30 +53,30 @@ function processPage(ctx: Hexo, file: _File) { file.stat(), file.read() ]).spread((stats: Stats, content: string) => { - const data = yfm(content); + const data: PageSchema = yfm(content); const output = ctx.render.getOutput(path); data.source = path; data.raw = content; - data.date = toDate(data.date); + data.date = toDate(data.date) as any; if (data.date) { - if (timezoneCfg) data.date = timezone(data.date, timezoneCfg); + if (timezoneCfg) data.date = timezone(data.date, timezoneCfg) as any; } else { - data.date = stats.ctime; + data.date = stats.ctime as any; } - data.updated = toDate(data.updated); + data.updated = toDate(data.updated) as any; if (data.updated) { - if (timezoneCfg) data.updated = timezone(data.updated, timezoneCfg); + if (timezoneCfg) data.updated = timezone(data.updated, timezoneCfg) as any; } else if (updated_option === 'date') { data.updated = data.date; } else if (updated_option === 'empty') { data.updated = undefined; } else { - data.updated = stats.mtime; + data.updated = stats.mtime as any; } if (data.permalink) { diff --git a/lib/plugins/processor/common.ts b/lib/plugins/processor/common.ts index 25b7a8c004..ca919b0b41 100644 --- a/lib/plugins/processor/common.ts +++ b/lib/plugins/processor/common.ts @@ -1,4 +1,3 @@ -import { Pattern } from 'hexo-util'; import moment from 'moment-timezone'; import micromatch from 'micromatch'; @@ -29,8 +28,8 @@ export {isTmpFile}; export {isHiddenFile}; export {isExcludedFile}; -export function toDate(date?: string | number | Date | moment.Moment) { - if (!date || moment.isMoment(date)) return date; +export function toDate(date?: string | number | Date | moment.Moment): Date | undefined | moment.Moment { + if (!date || moment.isMoment(date)) return date as any; if (!(date instanceof Date)) { date = new Date(date); diff --git a/lib/plugins/processor/post.ts b/lib/plugins/processor/post.ts index 0e185c5a77..76f35f2bd7 100644 --- a/lib/plugins/processor/post.ts +++ b/lib/plugins/processor/post.ts @@ -8,12 +8,12 @@ import { magenta } from 'picocolors'; import type { _File } from '../../box'; import type Hexo from '../../hexo'; import type { Stats } from 'fs'; -import { PostSchema } from '../../types'; +import { PostAssetSchema, PostSchema } from '../../types'; import type Document from 'warehouse/dist/document'; const postDir = '_posts/'; const draftDir = '_drafts/'; -let permalink; +let permalink: Permalink; const preservedKeys = { title: true, @@ -92,7 +92,7 @@ function processPost(ctx: Hexo, file: _File) { file.stat(), file.read() ]).spread((stats: Stats, content: string) => { - const data = yfm(content); + const data: PostSchema = yfm(content); const info = parseFilename(config.new_post_name, path); const keys = Object.keys(info); @@ -114,35 +114,36 @@ function processPost(ctx: Hexo, file: _File) { // use `slug` as `title` of post when `title` is not specified. // https://github.com/hexojs/hexo/issues/5372 if (use_slug_as_post_title && !('title' in data)) { + // @ts-expect-error - title is not in data data.title = info.title; } if (data.date) { - data.date = toDate(data.date); + data.date = toDate(data.date) as any; } else if (info && info.year && (info.month || info.i_month) && (info.day || info.i_day)) { data.date = new Date( info.year, parseInt(info.month || info.i_month, 10) - 1, parseInt(info.day || info.i_day, 10) - ); + ) as any; } if (data.date) { - if (timezoneCfg) data.date = timezone(data.date, timezoneCfg); + if (timezoneCfg) data.date = timezone(data.date, timezoneCfg) as any; } else { - data.date = stats.birthtime; + data.date = stats.birthtime as any; } - data.updated = toDate(data.updated); + data.updated = toDate(data.updated) as any; if (data.updated) { - if (timezoneCfg) data.updated = timezone(data.updated, timezoneCfg); + if (timezoneCfg) data.updated = timezone(data.updated, timezoneCfg) as any; } else if (updated_option === 'date') { data.updated = data.date; } else if (updated_option === 'empty') { data.updated = undefined; } else { - data.updated = stats.mtime; + data.updated = stats.mtime as any; } if (data.category && !data.categories) { @@ -183,7 +184,7 @@ function processPost(ctx: Hexo, file: _File) { } return Post.insert(data); - }).then(doc => Promise.all([ + }).then((doc: PostSchema) => Promise.all([ doc.setCategories(categories), doc.setTags(tags), scanAssetDir(ctx, doc) @@ -207,7 +208,7 @@ function parseFilename(config: string, path: string) { }); } - const data = permalink.parse(path); + const data = permalink.parse(path) as Record; if (data) { if (data.title !== undefined) { @@ -223,7 +224,7 @@ function parseFilename(config: string, path: string) { }; } -function scanAssetDir(ctx: Hexo, post) { +function scanAssetDir(ctx: Hexo, post: PostSchema) { if (!ctx.config.post_asset_folder) return; const assetDir = post.asset_dir; @@ -257,7 +258,7 @@ function scanAssetDir(ctx: Hexo, post) { }); } -function shouldSkipAsset(ctx: Hexo, post, asset) { +function shouldSkipAsset(ctx: Hexo, post: PostSchema, asset: Document) { if (!ctx._showDrafts()) { if (post.published === false && asset) { // delete existing draft assets if draft posts are hidden diff --git a/lib/types.ts b/lib/types.ts index 66b9e5827d..3d78ac548d 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -58,6 +58,11 @@ export interface TagSchema { length: number; } +export interface DataSchema { + id?: string; + data: any; +} + export interface CategorySchema { id?: string; _id?: string; @@ -92,74 +97,253 @@ export interface PostAssetSchema { source: string; } -export interface PostSchema { - id?: string; +export interface BasePagePostSchema { + + /** + * ID generated by warehouse + */ _id?: string; + + /** + * Article title + */ title: string; + + /** + * Article created date + */ date: moment.Moment, + + /** + * Article last updated date + */ updated: moment.Moment, + + /** + * Comment enabled or not + */ comments: boolean; - layout: string; + + /** + * Layout name + */ + layout: string | false; + + /** + * The full processed content of the article + */ _content: string; + + /** + * The full processed content of the article + */ + content?: string; + + /** + * The path of the source file + */ source: string; - slug: string; - photos?: string[]; + + /** + * The URL of the article without root URL. + * We usually use url_for(page.path) in theme. + */ + path: string; + + /** + * The raw data of the article + */ raw: string; - published: boolean; - content?: string; + + /** + * Article excerpt + */ excerpt?: string; + + /** + * Contents except article excerpt + */ more?: string; - author?: string; - asset_dir: string; + + /** + * Full path of the source file + */ full_source: string; - path: string; + + /** + * Full (encoded) URL of the article + */ permalink: string; - categories: Query; - tags?: Query; - __permalink?: string; - __post?: boolean; - canonical_path?: string; + + /** + * The photos of the article (Used in gallery posts) + */ + photos?: string[]; + + /** + * The external link of the article (Used in link posts) + */ + link?: string; + + /** + * The language of the article + */ lang?: string; + + /** + * The language of the article + */ language?: string; - prev?: PostSchema; - next?: PostSchema; + + /** + * Base URL + */ base?: string; - current?: number; - total?: number; - description?: string; + + /** + * Whether the page is a page + */ + __page?: boolean; + + /** + * Whether the page is a post + */ + __post?: boolean; + + /** + * Whether the page is a home page + */ + __index?: boolean; + + /** + * custom variables set in front-matter. + */ [key: string]: any; +} + +export interface PostSchema extends BasePagePostSchema { + + /** + * Post ID + */ + id?: string; + + /** + * The slug of the post + */ + slug: string; + + /** + * True if the post is not a draft + */ + published: boolean; + + /** + * The path of the asset directory + */ + asset_dir: string; + + /** + * All categories of the post + */ + categories: Query; + + /** + * All tags of the post + */ + tags: Query; + + /** + * Inner usage + */ + __permalink?: string; + + /** + * The previous post, `null` if the post is the first post + */ + prev?: PostSchema | null; + + /** + * The next post, `null` if the post is the last post + */ + next?: PostSchema | null; + notPublished: () => boolean; setTags: (tags: string[]) => any; setCategories: (cats: (string | string[])[]) => any; } -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; - full_source: string; - permalink: string; - author?: string; - tags?: any; - canonical_path?: string; - lang?: string; - language?: string; - __page?: boolean; - base?: string; - current?: number; +export interface PageSchema extends BasePagePostSchema { + + /** + * Posts displayed per page, only available on home page + */ + per_page?: number; + + /** + * Total number of pages, only available on home page + */ total?: number; - photos?: string[]; - description?: string; + + /** + * Current page number, only available on home page + */ + current?: number; + + /** + * The URL of current page, only available on home page + */ + current_url?: string; + + /** + * Posts in this page, only available on home page + */ + posts?: any; + + /** + * Previous page number. `0` if the current page is the first. only available on home page + */ + prev?: number; + + /** + * The URL of previous page. `''` if the current page is the first. only available on home page + */ + prev_link?: string; + + /** + * Next page number. `0` if the current page is the last. only available on home page + */ + next?: number; + + /** + * The URL of next page. `''` if the current page is the last. only available on home page + */ + next_link?: string; + + /** + * Equals true, only available on archive page + */ + archive?: boolean; + + /** + * Archive year (4-digit), only available on archive page + */ + year?: number; + + /** + * Archive month (2-digit without leading zeros), only available on archive page + */ + month?: number; + + /** + * Category name, only available on category page + */ + category?: string; + + /** + * Tag name, only available on tag page + */ + tag?: string; } export interface AssetSchema { @@ -177,7 +361,7 @@ export interface CacheSchema { } // Generator return types -export interface BasicGeneratorReturn { +export interface BaseGeneratorReturn { /** * Path not including the prefixing `/`. @@ -225,7 +409,7 @@ export interface LocalsType { /** * Page specific information and custom variables set in front-matter. */ - page: any; + page: BasePagePostSchema; /** * Path of current page @@ -261,7 +445,14 @@ export interface LocalsType { cache?: boolean; // i18n properties from i18nLocalsFilter + /** + * https://hexo.io/docs/internationalization#Templates + */ __: ReturnType; + + /** + * https://hexo.io/docs/internationalization#Templates + */ _p: ReturnType; // result after renderer.compile diff --git a/test/scripts/generators/page.ts b/test/scripts/generators/page.ts index 958f20d79a..c0b74af633 100644 --- a/test/scripts/generators/page.ts +++ b/test/scripts/generators/page.ts @@ -2,7 +2,7 @@ import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import pageGenerator from '../../../lib/plugins/generator/page'; import chai from 'chai'; -import { BasicGeneratorReturn } from '../../../lib/types'; +import { BaseGeneratorReturn } from '../../../lib/types'; const should = chai.should(); type PageGeneratorParams = Parameters; type PageGeneratorReturn = ReturnType; @@ -42,7 +42,7 @@ describe('page', () => { path: 'bar', layout: 'photo' }); - const data = await generator(locals()) as BasicGeneratorReturn[]; + const data = await generator(locals()) as BaseGeneratorReturn[]; data[0].layout!.should.eql(['photo', 'page', 'post', 'index']); page.remove(); @@ -55,7 +55,7 @@ describe('page', () => { path: 'bar', layout }); - const data = await generator(locals()) as BasicGeneratorReturn[]; + const data = await generator(locals()) as BaseGeneratorReturn[]; should.not.exist(data[0].layout); page.remove(); diff --git a/test/scripts/generators/post.ts b/test/scripts/generators/post.ts index 93990d69f6..09d1675bb7 100644 --- a/test/scripts/generators/post.ts +++ b/test/scripts/generators/post.ts @@ -1,7 +1,7 @@ import BluebirdPromise from 'bluebird'; import Hexo from '../../../lib/hexo'; import postGenerator from '../../../lib/plugins/generator/post'; -import { BasicGeneratorReturn } from '../../../lib/types'; +import { BaseGeneratorReturn } from '../../../lib/types'; import chai from 'chai'; const should = chai.should(); type PostGeneratorParams = Parameters; @@ -46,7 +46,7 @@ describe('post', () => { slug: 'bar', layout: 'photo' }); - const data = await generator(locals()) as BasicGeneratorReturn[]; + const data = await generator(locals()) as BaseGeneratorReturn[]; data[0].layout!.should.eql(['photo', 'post', 'page', 'index']); post.remove(); @@ -58,7 +58,7 @@ describe('post', () => { slug: 'bar', layout: false }); - const data = await generator(locals()) as BasicGeneratorReturn[]; + const data = await generator(locals()) as BaseGeneratorReturn[]; should.not.exist(data[0].layout); post.remove(); @@ -70,7 +70,7 @@ describe('post', () => { {source: 'bar', slug: 'bar', date: 1e8 + 1}, {source: 'baz', slug: 'baz', date: 1e8 - 1} ]); - const data = await generator(locals()) as BasicGeneratorReturn[]; + const data = await generator(locals()) as BaseGeneratorReturn[]; should.not.exist(data[0].data.prev); data[0].data.next!._id!.should.eq(posts[0]._id); data[1].data.prev!._id!.should.eq(posts[1]._id);