From 8b95bbc722e5c77a7e8125441ed64d2ea3524ac0 Mon Sep 17 00:00:00 2001 From: Kagamigawa <35628460+KagamigawaMeguri@users.noreply.github.com> Date: Mon, 1 May 2023 22:30:53 +0800 Subject: [PATCH 01/24] fix(post-asset): strip extensions better on permalink (#5153) * compatible with hexo-abbrlink * strip extensions better on permalink --- lib/models/post_asset.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/models/post_asset.js b/lib/models/post_asset.js index 9c3c3778f8..656acdbac4 100644 --- a/lib/models/post_asset.js +++ b/lib/models/post_asset.js @@ -1,7 +1,7 @@ 'use strict'; const { Schema } = require('warehouse').default; -const { join } = require('path'); +const { join, dirname } = require('path'); module.exports = ctx => { const PostAsset = new Schema({ @@ -19,8 +19,8 @@ module.exports = ctx => { // PostAsset.path is file path relative to `public_dir` // no need to urlescape, #1562 - // strip /\.html?$/ extensions on permalink, #2134 - return join(post.path.replace(/\.html?$/, ''), this.slug); + // strip extensions better on permalink, #2134 + return join(dirname(post.path), post.slug, this.slug); }); PostAsset.virtual('source').get(function() { From 981560f51dcb6b480fd8c10e3554c3c1b1422076 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Jun 2023 19:36:42 +0900 Subject: [PATCH 02/24] chore: bump c8 from 7.14.0 to 8.0.0 (#5227) Bumps [c8](https://github.com/bcoe/c8) from 7.14.0 to 8.0.0. - [Release notes](https://github.com/bcoe/c8/releases) - [Changelog](https://github.com/bcoe/c8/blob/main/CHANGELOG.md) - [Commits](https://github.com/bcoe/c8/compare/v7.14.0...v8.0.0) --- updated-dependencies: - dependency-name: c8 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c8fc3c53da..22194c1ad8 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "devDependencies": { "@easyops/git-exec-and-restage": "^1.0.4", "0x": "^5.1.2", - "c8": "^7.12.0", + "c8": "^8.0.0", "chai": "^4.3.6", "cheerio": "0.22.0", "decache": "^4.6.1", From b267475d306b616ab9a3cd37e904d36524aad8be Mon Sep 17 00:00:00 2001 From: yoshinorin Date: Wed, 26 Jul 2023 00:17:19 +0900 Subject: [PATCH 03/24] chore(github): delete `other` issue template (#5248) --- .github/ISSUE_TEMPLATE/other.md | 58 --------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/other.md diff --git a/.github/ISSUE_TEMPLATE/other.md b/.github/ISSUE_TEMPLATE/other.md deleted file mode 100644 index 6d0d667285..0000000000 --- a/.github/ISSUE_TEMPLATE/other.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: Other -about: Not a question, feature-request, bug -title: '' -labels: '' -assignees: '' - ---- - - - -## Check List - -Please check followings before submitting a new issue. - -- [ ] I have already confirmed other issue template and they are not different my want -- [ ] Not a question, feature-request, bug - - Please submit to [discussion](https://github.com/hexojs/hexo/discussions) if your issue is a question. - -## Information - - - -## Environment & Settings - -**Node.js & npm version** - -``` -``` - -**Your site `_config.yml`** (Optional) - -``` -``` - -**Hexo and Plugin version(`npm ls --depth 0`)** - -``` -``` - -**Your package.json `package.json`** - -``` -``` - -## Others - - From 99e94cc452693b70cbbe61bfb326fb3072a77cbf Mon Sep 17 00:00:00 2001 From: Mimi <1119186082@qq.com> Date: Thu, 27 Jul 2023 19:42:09 +0800 Subject: [PATCH 04/24] feat(post): remove front-matter property `link` (#5253) --- lib/models/post.ts | 1 - lib/plugins/processor/post.ts | 4 ---- test/scripts/models/post.js | 1 - test/scripts/processors/post.js | 28 +--------------------------- 4 files changed, 1 insertion(+), 33 deletions(-) diff --git a/lib/models/post.ts b/lib/models/post.ts index 60695323ec..56e9f8cf6f 100644 --- a/lib/models/post.ts +++ b/lib/models/post.ts @@ -34,7 +34,6 @@ export = ctx => { source: {type: String, required: true}, slug: {type: String, required: true}, photos: [String], - link: {type: String, default: ''}, raw: {type: String, default: ''}, published: {type: Boolean, default: true}, content: {type: String}, diff --git a/lib/plugins/processor/post.ts b/lib/plugins/processor/post.ts index dca6306e62..e433858084 100644 --- a/lib/plugins/processor/post.ts +++ b/lib/plugins/processor/post.ts @@ -159,10 +159,6 @@ function processPost(ctx, file) { data.photos = [data.photos]; } - if (data.link && !data.title) { - data.title = data.link.replace(/^https?:\/\/|\/$/g, ''); - } - if (data.permalink) { data.__permalink = data.permalink; data.permalink = undefined; diff --git a/test/scripts/models/post.js b/test/scripts/models/post.js index e2bf189da0..ded1dc66be 100644 --- a/test/scripts/models/post.js +++ b/test/scripts/models/post.js @@ -31,7 +31,6 @@ describe('Post', () => { data.comments.should.be.true; data.layout.should.eql('post'); data._content.should.eql(''); - data.link.should.eql(''); data.raw.should.eql(''); data.published.should.be.true; should.not.exist(data.updated); diff --git a/test/scripts/processors/post.js b/test/scripts/processors/post.js index 9cb00b3ac7..1beb68207f 100644 --- a/test/scripts/processors/post.js +++ b/test/scripts/processors/post.js @@ -778,33 +778,7 @@ describe('post', () => { ]); }); - it('post - link without title', async () => { - const body = [ - 'link: https://hexo.io/', - '---' - ].join('\n'); - - const file = newFile({ - path: 'foo.html', - published: true, - type: 'create', - renderable: true - }); - - await writeFile(file.source, body); - await process(file); - const post = Post.findOne({ source: file.path }); - - post.link.should.eql('https://hexo.io/'); - post.title.should.eql('hexo.io'); - - return Promise.all([ - post.remove(), - unlink(file.source) - ]); - }); - - it('post - link without title and link', async () => { + it('post - without title', async () => { const body = ''; const file = newFile({ From 5d8dcecbb2d2e3a2f21c3b20b79393d4cf7ae7cd Mon Sep 17 00:00:00 2001 From: Mimi <1119186082@qq.com> Date: Wed, 2 Aug 2023 00:49:37 +0800 Subject: [PATCH 05/24] Revert "fix(backtick_code): handle empty code blocks (#5206)" (#5257) This reverts commit c62909deb607ea104a74c84e83846ca0b0758221. --- .../before_post_render/backtick_code_block.ts | 2 +- test/scripts/filters/backtick_code_block.js | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/lib/plugins/filter/before_post_render/backtick_code_block.ts b/lib/plugins/filter/before_post_render/backtick_code_block.ts index 802ed7edd3..b9df3e60f2 100644 --- a/lib/plugins/filter/before_post_render/backtick_code_block.ts +++ b/lib/plugins/filter/before_post_render/backtick_code_block.ts @@ -1,4 +1,4 @@ -const rBacktick = /^((?:[^\S\r\n]*>){0,3}[^\S\r\n]*)(`{3,}|~{3,})[^\S\r\n]*((?:.*?[^`\s])?)[^\S\r\n]*\n((?:[\s\S]*?\n)*?)(?:(?:[^\S\r\n]*>){0,3}[^\S\r\n]*)\2[^\S\r\n]?(\n+|$)/gm; +const rBacktick = /^((?:[^\S\r\n]*>){0,3}[^\S\r\n]*)(`{3,}|~{3,})[^\S\r\n]*((?:.*?[^`\s])?)[^\S\r\n]*\n((?:[\s\S]*?\n)?)(?:(?:[^\S\r\n]*>){0,3}[^\S\r\n]*)\2[^\S\r\n]?(\n+|$)/gm; const rAllOptions = /([^\s]+)\s+(.+?)\s+(https?:\/\/\S+|\/\S+)\s*(.+)?/; const rLangCaption = /([^\s]+)\s*(.+)?/; diff --git a/test/scripts/filters/backtick_code_block.js b/test/scripts/filters/backtick_code_block.js index b195d76a8e..5c75bbccdb 100644 --- a/test/scripts/filters/backtick_code_block.js +++ b/test/scripts/filters/backtick_code_block.js @@ -650,19 +650,5 @@ describe('Backtick code block', () => { codeBlock(data); data.content.should.eql('' + expected + ''); }); - - it('handle empty code block', () => { - const data = { - content: [ - '``` js', - '```', - '# New line', - '``` js', - '```' - ].join('\n') - }; - codeBlock(data); - data.content.match(//g).length.should.eql(2); - }); }); }); From 35ceaae7a57b366744857b52f8bfa08070930d1d Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Wed, 2 Aug 2023 00:50:25 +0800 Subject: [PATCH 06/24] fix(post): skip_render not working in post_asset_folder (#5258) --- lib/plugins/processor/post.ts | 6 ++- test/scripts/processors/post.js | 72 +++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/lib/plugins/processor/post.ts b/lib/plugins/processor/post.ts index e433858084..9c61a561b8 100644 --- a/lib/plugins/processor/post.ts +++ b/lib/plugins/processor/post.ts @@ -217,7 +217,9 @@ function scanAssetDir(ctx, post) { const assetDir = post.asset_dir; const baseDir = ctx.base_dir; + const sourceDir = ctx.config.source_dir; const baseDirLength = baseDir.length; + const sourceDirLength = sourceDir.length; const PostAsset = ctx.model('PostAsset'); return stat(assetDir).then(stats => { @@ -229,6 +231,7 @@ function scanAssetDir(ctx, post) { throw err; }).filter(item => !isExcludedFile(item, ctx.config)).map(item => { const id = join(assetDir, item).substring(baseDirLength).replace(/\\/g, '/'); + const renderablePath = id.substring(sourceDirLength + 1); const asset = PostAsset.findById(id); if (shouldSkipAsset(ctx, post, asset)) return undefined; @@ -237,7 +240,8 @@ function scanAssetDir(ctx, post) { _id: id, post: post._id, slug: item, - modified: true + modified: true, + renderable: ctx.render.isRenderable(renderablePath) && !isMatch(renderablePath, ctx.config.skip_render) }); }); } diff --git a/test/scripts/processors/post.js b/test/scripts/processors/post.js index 1beb68207f..fea2563d62 100644 --- a/test/scripts/processors/post.js +++ b/test/scripts/processors/post.js @@ -1256,4 +1256,76 @@ describe('post', () => { unlink(file.source) ]); }); + + it('asset - post - common render', async () => { + hexo.config.post_asset_folder = true; + + const file = newFile({ + path: 'foo.md', + published: true, + type: 'create', + renderable: true + }); + + const assetFile = newFile({ + path: 'foo/test.yml', + published: true, + type: 'create' + }); + + await Promise.all([ + writeFile(file.source, 'test'), + writeFile(assetFile.source, 'test') + ]); + await process(file); + const id = 'source/' + assetFile.path; + const post = Post.findOne({ source: file.path }); + PostAsset.findById(id).renderable.should.be.true; + + hexo.config.post_asset_folder = false; + + return Promise.all([ + unlink(file.source), + unlink(assetFile.source), + post.remove(), + PostAsset.removeById(id) + ]); + }); + + it('asset - post - skip render', async () => { + hexo.config.post_asset_folder = true; + hexo.config.skip_render = '**.yml'; + + const file = newFile({ + path: 'foo.md', + published: true, + type: 'create', + renderable: true + }); + + const assetFile = newFile({ + path: 'foo/test.yml', + published: true, + type: 'create' + }); + + await Promise.all([ + writeFile(file.source, 'test'), + writeFile(assetFile.source, 'test') + ]); + await process(file); + const id = 'source/' + assetFile.path; + const post = Post.findOne({ source: file.path }); + PostAsset.findById(id).renderable.should.be.false; + + hexo.config.post_asset_folder = false; + hexo.config.skip_render = ''; + + return Promise.all([ + unlink(file.source), + unlink(assetFile.source), + post.remove(), + PostAsset.removeById(id) + ]); + }); }); From 24a7b61942a122d8f5f8886dcd03a2e9e9e8ad59 Mon Sep 17 00:00:00 2001 From: Dimas Lanjaka Date: Thu, 10 Aug 2023 17:04:43 +0700 Subject: [PATCH 07/24] feat: define global variable hexo (#5242) useful for plugin written in typescript or let IDE detecting it --- lib/hexo/index.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/hexo/index.ts b/lib/hexo/index.ts index e8c06b83d4..21c14183fb 100644 --- a/lib/hexo/index.ts +++ b/lib/hexo/index.ts @@ -598,4 +598,11 @@ Hexo.prototype.core_dir = Hexo.core_dir; Hexo.version = version; Hexo.prototype.version = Hexo.version; +// define global variable +// this useful for plugin written in typescript +declare global { + // eslint-disable-next-line one-var + const hexo: Hexo; +} + export = Hexo; From d29d774c100e373b937d5329932506143a9cb8eb Mon Sep 17 00:00:00 2001 From: Uiolee <22849383+uiolee@users.noreply.github.com> Date: Fri, 1 Sep 2023 00:51:45 +0800 Subject: [PATCH 08/24] chore(lint-staged): remove `git-exec-and-restage` (#5281) --- .lintstagedrc | 3 --- .lintstagedrc.json | 4 ++++ package.json | 5 ++--- 3 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 .lintstagedrc create mode 100644 .lintstagedrc.json diff --git a/.lintstagedrc b/.lintstagedrc deleted file mode 100644 index 66886867d5..0000000000 --- a/.lintstagedrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "*.js": "git-exec-and-restage eslint --fix --" -} diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 0000000000..6953073375 --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,4 @@ +{ + "*.js": "eslint --fix", + "*.ts": "eslint --fix" +} diff --git a/package.json b/package.json index 8080a1db88..cc7f6a65e9 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,6 @@ }, "devDependencies": { "0x": "^5.1.2", - "@easyops/git-exec-and-restage": "^1.0.4", "@types/bluebird": "^3.5.37", "@types/node": "^18.11.8", "@types/nunjucks": "^3.2.2", @@ -77,11 +76,11 @@ "chai": "^4.3.6", "cheerio": "0.22.0", "decache": "^4.6.1", - "eslint": "^8.8.0", + "eslint": "^8.48.0", "eslint-config-hexo": "^5.0.0", "hexo-renderer-marked": "^6.0.0", "husky": "^8.0.1", - "lint-staged": "^13.0.3", + "lint-staged": "^14.0.1", "mocha": "^10.0.0", "sinon": "^15.0.0", "ts-node": "^10.9.1", From 7b588e78aae57e756e4d18bcd78e63d9dc7d34cd Mon Sep 17 00:00:00 2001 From: Uiolee <22849383+uiolee@users.noreply.github.com> Date: Sat, 2 Sep 2023 02:25:37 +0800 Subject: [PATCH 09/24] ci: reduce the running of ci (#5282) --- .github/workflows/linter.yml | 17 +++++++++++++++-- .github/workflows/tester.yml | 25 ++++++++++++++++++++----- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index d3d9678043..8211d38999 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -1,6 +1,19 @@ name: Linter -on: [push, pull_request] +on: + push: + branches: + - "master" + - "v7.0.0" + paths: + - "lib/**" + - "test/**" + - ".github/workflows/linter.yml" + pull_request: + paths: + - "lib/**" + - "test/**" + - ".github/workflows/linter.yml" permissions: contents: read @@ -13,7 +26,7 @@ jobs: - name: Use Node.js 14.x uses: actions/setup-node@v3 with: - node-version: '14.x' + node-version: "14.x" - name: Install Dependencies run: npm install - name: Lint diff --git a/.github/workflows/tester.yml b/.github/workflows/tester.yml index a28cf0a77d..c245376116 100644 --- a/.github/workflows/tester.yml +++ b/.github/workflows/tester.yml @@ -1,6 +1,21 @@ name: Tester -on: [push, pull_request] +on: + push: + branches: + - "master" + - "v7.0.0" + paths: + - "lib/**" + - "test/**" + - "package.json" + - ".github/workflows/tester.yml" + pull_request: + paths: + - "lib/**" + - "test/**" + - "package.json" + - ".github/workflows/tester.yml" permissions: contents: read @@ -11,7 +26,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - node-version: ['14.x', '16.x', '18.x'] + node-version: ["14.x", "16.x", "18.x"] fail-fast: false steps: - uses: actions/checkout@v3 @@ -27,13 +42,13 @@ jobs: CI: true coverage: permissions: - checks: write # for coverallsapp/github-action to create new checks - contents: read # for actions/checkout to fetch code + checks: write # for coverallsapp/github-action to create new checks + contents: read # for actions/checkout to fetch code runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest] - node-version: ['14.x'] + node-version: ["14.x"] steps: - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} From 4707a2d33b93052d0e3e3781d8f4313febd2d5cb Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Mon, 9 Oct 2023 15:56:42 +0800 Subject: [PATCH 10/24] Revert "fix(post-asset): strip extensions better on permalink (#5153)" (#5308) This reverts commit 8b95bbc722e5c77a7e8125441ed64d2ea3524ac0. --- lib/models/post_asset.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/models/post_asset.js b/lib/models/post_asset.js index 656acdbac4..9c3c3778f8 100644 --- a/lib/models/post_asset.js +++ b/lib/models/post_asset.js @@ -1,7 +1,7 @@ 'use strict'; const { Schema } = require('warehouse').default; -const { join, dirname } = require('path'); +const { join } = require('path'); module.exports = ctx => { const PostAsset = new Schema({ @@ -19,8 +19,8 @@ module.exports = ctx => { // PostAsset.path is file path relative to `public_dir` // no need to urlescape, #1562 - // strip extensions better on permalink, #2134 - return join(dirname(post.path), post.slug, this.slug); + // strip /\.html?$/ extensions on permalink, #2134 + return join(post.path.replace(/\.html?$/, ''), this.slug); }); PostAsset.virtual('source').get(function() { From ad056527cee2c55fa961cc84a56f44ea55404c63 Mon Sep 17 00:00:00 2001 From: Uiolee <22849383+uiolee@users.noreply.github.com> Date: Mon, 9 Oct 2023 15:57:32 +0800 Subject: [PATCH 11/24] ci: reduce the running of ci (#5291) --- .github/workflows/linter.yml | 17 +++++++++++++++-- .github/workflows/tester.yml | 25 ++++++++++++++++++++----- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index d3d9678043..8211d38999 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -1,6 +1,19 @@ name: Linter -on: [push, pull_request] +on: + push: + branches: + - "master" + - "v7.0.0" + paths: + - "lib/**" + - "test/**" + - ".github/workflows/linter.yml" + pull_request: + paths: + - "lib/**" + - "test/**" + - ".github/workflows/linter.yml" permissions: contents: read @@ -13,7 +26,7 @@ jobs: - name: Use Node.js 14.x uses: actions/setup-node@v3 with: - node-version: '14.x' + node-version: "14.x" - name: Install Dependencies run: npm install - name: Lint diff --git a/.github/workflows/tester.yml b/.github/workflows/tester.yml index a28cf0a77d..c245376116 100644 --- a/.github/workflows/tester.yml +++ b/.github/workflows/tester.yml @@ -1,6 +1,21 @@ name: Tester -on: [push, pull_request] +on: + push: + branches: + - "master" + - "v7.0.0" + paths: + - "lib/**" + - "test/**" + - "package.json" + - ".github/workflows/tester.yml" + pull_request: + paths: + - "lib/**" + - "test/**" + - "package.json" + - ".github/workflows/tester.yml" permissions: contents: read @@ -11,7 +26,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - node-version: ['14.x', '16.x', '18.x'] + node-version: ["14.x", "16.x", "18.x"] fail-fast: false steps: - uses: actions/checkout@v3 @@ -27,13 +42,13 @@ jobs: CI: true coverage: permissions: - checks: write # for coverallsapp/github-action to create new checks - contents: read # for actions/checkout to fetch code + checks: write # for coverallsapp/github-action to create new checks + contents: read # for actions/checkout to fetch code runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest] - node-version: ['14.x'] + node-version: ["14.x"] steps: - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} From f173abcb7be7c3d0580fcacc66e7602490bdd42b Mon Sep 17 00:00:00 2001 From: Uiolee <22849383+uiolee@users.noreply.github.com> Date: Sun, 22 Oct 2023 01:47:43 +0800 Subject: [PATCH 12/24] chore(github): use github issue form (#5319) Co-authored-by: D-Sketon <2055272094@qq.com> --- .github/ISSUE_TEMPLATE/bug_report.md | 93 ----------- .github/ISSUE_TEMPLATE/bug_report.yml | 148 ++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 2 +- .../feature-request-improvement.md | 23 --- .../feature-request-improvement.yml | 36 +++++ 5 files changed, 185 insertions(+), 117 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature-request-improvement.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-improvement.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 353fae2aca..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -name: Bug report -about: Something isn't working as expected -title: '' -labels: '' -assignees: '' - ---- - - - -## Check List - -Please check followings before submitting a new issue. - -- [ ] I have already read [Docs page](https://hexo.io/docs/) & [Troubleshooting page](https://hexo.io/docs/troubleshooting) -- [ ] I have already searched existing issues and they are not help to me -- [ ] I examined error or warning messages and it's difficult to solve -- [ ] Using [the latest](https://github.com/hexojs/hexo/releases) version of Hexo (run `hexo version` to check) -- [ ] Node.js is higher than [minimum required version](https://hexo.io/docs/#Minimum-required-Node-js-version) - -## Expected behavior - -## Actual behavior - -## How to reproduce? - -* Step1 -* Step2 -* etc... - -## Is the problem still there under "Safe mode"? - - - -## Environment & Settings - -**Node.js & npm version(`node -v && npm -v`)** - - - -``` -``` - -**Your site `_config.yml`** (Optional) - - - -```yaml -``` - -**Hexo and Plugin version(`npm ls --depth 0`)** - - - -``` -``` - -**Your package.json `package.json`** - - - -``` -``` - -## Others - - diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000000..4c1e219d45 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,148 @@ +name: Bug report +description: Something isn't working as expected. +# title: "" +# labels: [] +# assignees: [] + +body: + - type: markdown + attributes: + value: | + ## Tips + + - 给简体中文用户的提示: + + - 在提交 issue 时请按照下面的模板提供相关信息,这将有助于我们发现问题。 + - 请尽量使用英语描述你遇到的问题,这可以让更多的人帮助到你。 + + - A good bug report should have your configuration and build environment information, which are essential for us to investigate the problem. We've provided the following steps on how to attach the necessary information. + + - If you find that markdown files are not rendered as expected, please go to https://marked.js.org/demo/ to see if it can be reproduced there. If it can be reproduced, please file a bug to https://github.com/markedjs/marked. + + - If you want help on your bug, please also send us the git repository (GitHub, GitLab, Bitbucket, etc.) where your hexo code is stored. It would greatly help. If you prefer not to have your hexo code out in public, please upload to a private GitHub repository and grant read-only access to `hexojs/core`. + + - Please take extra precaution not to attach any secret or personal information. (likes personal privacy, password, GitHub Personal Access Token, etc.) + + ------ + + - type: checkboxes + validations: + required: true + attributes: + label: Check List + description: Please check followings before submitting a new issue. + options: + - label: I have already read [Docs page](https://hexo.io/docs/) & [Troubleshooting page](https://hexo.io/docs/troubleshooting). + - label: I have already searched existing issues and they are not help to me. + - label: I examined error or warning messages and it's difficult to solve. + - label: I am using the [latest](https://github.com/hexojs/hexo/releases) version of Hexo. (run `hexo version` to check) + - label: My Node.js is matched [the required version](https://hexo.io/docs/#Required-Node-js-version). + + - type: textarea + validations: + required: true + attributes: + label: Expected behavior + # description: + placeholder: Descripe what you expected to happen. + # value: + # render: + + - type: textarea + validations: + required: true + attributes: + label: Actual behavior + # description: + placeholder: Descripe what actually happen. + # value: + # render: + + - type: textarea + validations: + required: true + attributes: + label: How to reproduce? + description: How do you trigger this bug? Please walk us through it step by step. + placeholder: | + 1. Step1 + 2. Step2 + 3. etc. + ... + # value: + # render: + + - type: input + validations: + required: true + attributes: + label: Is the problem still there under `Safe mode`? + description: | + https://hexo.io/docs/commands#Safe-mode + + "Safe mode" will disable all the plugins and scripts. + If your problem disappear under "Safe mode" means the problem is probably at your newly installed plugins, not at hexo. + # placeholder: + # value: | + # render: + + - type: markdown + attributes: + value: | + ------ + + ## Environment & Settings + + - type: textarea + validations: + required: false + attributes: + label: Your Node.js & npm version + description: | + Please run `node -v && npm -v` + and paste the output here. + placeholder: node -v && npm -v + # value: | + render: text + + - type: textarea + validations: + required: false + attributes: + label: Your Hexo and Plugin version + description: | + Please run `npm ls --depth 0` + and paste the output here. + placeholder: npm ls --depth 0 + # value: + render: text + + - type: textarea + validations: + required: false + attributes: + label: Your `package.json` + description: Please paste the content of `package.json` here. + placeholder: package.json + # value: + render: json + + - type: textarea + validations: + required: false + attributes: + label: Your site's `_config.yml` (Optional) + description: Please paste the content of your `_config.yml` here. + placeholder: _config.yml + # value: | + render: yaml + + - type: textarea + validations: + required: false + attributes: + label: Others + description: If you have other information. Please write here. + # placeholder: + # value: + # render: diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 3c6bdca6bd..5548b4bc8c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,4 +2,4 @@ blank_issues_enabled: false contact_links: - name: Ask a Question, Help, Discuss url: https://github.com/hexojs/hexo/discussions - about: I have a question, help for hexo (e.g. Customize) \ No newline at end of file + about: I have a question, help for hexo (e.g. Customize) diff --git a/.github/ISSUE_TEMPLATE/feature-request-improvement.md b/.github/ISSUE_TEMPLATE/feature-request-improvement.md deleted file mode 100644 index 46f8ad6691..0000000000 --- a/.github/ISSUE_TEMPLATE/feature-request-improvement.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -name: Feature request / Improvement -about: I have a feature request, suggestion, improvement etc... -title: '' -labels: '' -assignees: '' - ---- - -## Check List - -Please check followings before submitting a new feature request. - -- [ ] I have already read [Docs page](https://hexo.io/docs/) -- [ ] I have already searched existing issues - -## Feature Request - - - -## Others - - diff --git a/.github/ISSUE_TEMPLATE/feature-request-improvement.yml b/.github/ISSUE_TEMPLATE/feature-request-improvement.yml new file mode 100644 index 0000000000..32db67e4e2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-improvement.yml @@ -0,0 +1,36 @@ +name: Feature request / Improvement +description: I have a feature request, suggestion, improvement etc... +# title: "" +# labels: [] +# assignees: [] + +body: + - type: checkboxes + validations: + required: true + attributes: + label: Check List + description: Please check followings before submitting a new feature request. + options: + - label: I have already read [Docs page](https://hexo.io/docs/). + - label: I have already searched existing issues. + + - type: textarea + validations: + required: true + attributes: + label: Feature Request + description: Descripe the feature and why it is needed. + # placeholder: + # value: + # render: + + - type: textarea + validations: + required: false + attributes: + label: Others + description: If you have other information. Please write here. + # placeholder: + # value: + # render: From 3059fa074a832a948ba5560798e094a503309541 Mon Sep 17 00:00:00 2001 From: Sukka Date: Sun, 22 Oct 2023 03:56:56 +0800 Subject: [PATCH 13/24] perf(post): cache tags getter (#5145) Co-authored-by: uiolee <22849383+uiolee@users.noreply.github.com> --- lib/models/post.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/models/post.ts b/lib/models/post.ts index 56e9f8cf6f..10b274d7ad 100644 --- a/lib/models/post.ts +++ b/lib/models/post.ts @@ -3,7 +3,7 @@ import moment from 'moment'; import { extname, join, sep } from 'path'; import Promise from 'bluebird'; import Moment from './types/moment'; -import { full_url_for } from 'hexo-util'; +import { full_url_for, Cache } from 'hexo-util'; function pickID(data) { return data._id; @@ -13,6 +13,8 @@ function removeEmptyTag(tags) { return tags.filter(tag => tag != null && tag !== '').map(tag => `${tag}`); } +const tagsGetterCache = new Cache(); + export = ctx => { const Post = new warehouse.Schema({ id: String, @@ -60,12 +62,14 @@ export = ctx => { }); Post.virtual('tags').get(function() { - const PostTag = ctx.model('PostTag'); - const Tag = ctx.model('Tag'); + return tagsGetterCache.apply(this._id, () => { + const PostTag = ctx.model('PostTag'); + const Tag = ctx.model('Tag'); - const ids = PostTag.find({post_id: this._id}, {lean: true}).map(item => item.tag_id); + const ids = PostTag.find({post_id: this._id}, {lean: true}).map(item => item.tag_id); - return Tag.find({_id: {$in: ids}}); + return Tag.find({_id: {$in: ids}}); + }); }); Post.method('notPublished', function() { @@ -79,6 +83,7 @@ export = ctx => { // If the post is unpublished then the tag needs to be removed, thus the function cannot be returned early here tags = []; } + tagsGetterCache.flush(); tags = removeEmptyTag(tags); const PostTag = ctx.model('PostTag'); From 2a2cc9a89f3f291d2ba93e3a4d7eeb3b8ba98bbe Mon Sep 17 00:00:00 2001 From: Mimi <1119186082@qq.com> Date: Mon, 23 Oct 2023 13:38:39 +0800 Subject: [PATCH 14/24] revert: Access data files from source folder (#1969) (#5325) --- lib/hexo/index.ts | 2 +- .../filter/before_generate/render_post.ts | 3 +-- test/scripts/filters/render_post.js | 16 ---------------- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/lib/hexo/index.ts b/lib/hexo/index.ts index 21c14183fb..2d347c7bde 100644 --- a/lib/hexo/index.ts +++ b/lib/hexo/index.ts @@ -555,7 +555,7 @@ class Hexo extends EventEmitter { this.emit('generateBefore'); // Run before_generate filters - return this.execFilter('before_generate', this.locals.get('data'), { context: this }) + return this.execFilter('before_generate', null, { context: this }) .then(() => this._routerRefresh(this._runGenerators(), useCache)).then(() => { this.emit('generateAfter'); diff --git a/lib/plugins/filter/before_generate/render_post.ts b/lib/plugins/filter/before_generate/render_post.ts index ae202e9477..539b5dadda 100644 --- a/lib/plugins/filter/before_generate/render_post.ts +++ b/lib/plugins/filter/before_generate/render_post.ts @@ -1,12 +1,11 @@ import Promise from 'bluebird'; -function renderPostFilter(data) { +function renderPostFilter() { const renderPosts = model => { const posts = model.toArray().filter(post => post.content == null); return Promise.map(posts, (post: any) => { post.content = post._content; - post.site = {data}; return this.post.render(post.full_source, post).then(() => post.save()); }); diff --git a/test/scripts/filters/render_post.js b/test/scripts/filters/render_post.js index ab82f405b3..e5540cc7e4 100644 --- a/test/scripts/filters/render_post.js +++ b/test/scripts/filters/render_post.js @@ -46,20 +46,4 @@ describe('Render post', () => { page.remove(); }); - it('use data variables', async () => { - let page = await Page.insert({ - source: 'foo.md', - path: 'foo.html', - _content: '

Hello {{site.data.foo.name}}

' - }); - - const id = page._id; - await renderPost({foo: {name: 'Hexo'}}); - - page = Page.findById(id); - page.content.trim().should.eql('

Hello Hexo

'); - - page.remove(); - }); - }); From 40fa970872c04ecc9e925ac88635705516523fa5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Oct 2023 00:10:16 +0800 Subject: [PATCH 15/24] chore: bump actions/setup-node from 3 to 4 (#5327) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/benchmark.yml | 4 ++-- .github/workflows/linter.yml | 2 +- .github/workflows/tester.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index b6c1a4ec00..ee60eb500a 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: Install dependencies @@ -38,7 +38,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: Install dependencies diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 8211d38999..4c407e1f76 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -24,7 +24,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Use Node.js 14.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "14.x" - name: Install Dependencies diff --git a/.github/workflows/tester.yml b/.github/workflows/tester.yml index c245376116..8ec0a3de1f 100644 --- a/.github/workflows/tester.yml +++ b/.github/workflows/tester.yml @@ -31,7 +31,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: Install Dependencies @@ -52,7 +52,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: Install Dependencies From 268882b19a9a8510ce7df7d8a978ba2dd130d7be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Oct 2023 00:14:53 +0800 Subject: [PATCH 16/24] chore: bump actions/checkout from 3 to 4 (#5288) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/benchmark.yml | 4 ++-- .github/workflows/linter.yml | 2 +- .github/workflows/tester.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index ee60eb500a..a822f5f5dc 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -19,7 +19,7 @@ jobs: node-version: ['14', '16', '18'] fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: @@ -36,7 +36,7 @@ jobs: node-version: ['14', '16', '18'] fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 4c407e1f76..a4f1c7cfd1 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -22,7 +22,7 @@ jobs: linter: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js 14.x uses: actions/setup-node@v4 with: diff --git a/.github/workflows/tester.yml b/.github/workflows/tester.yml index 8ec0a3de1f..700cda5872 100644 --- a/.github/workflows/tester.yml +++ b/.github/workflows/tester.yml @@ -29,7 +29,7 @@ jobs: node-version: ["14.x", "16.x", "18.x"] fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: @@ -50,7 +50,7 @@ jobs: os: [ubuntu-latest] node-version: ["14.x"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: From b898f294eb23e2402f7fd4f7ee1f96ed39766c6d Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Tue, 31 Oct 2023 20:52:26 +0800 Subject: [PATCH 17/24] refactor: refact types (#5271) --- lib/box/file.ts | 18 +++--- lib/box/index.ts | 55 ++++++++++-------- lib/extend/console.ts | 4 +- lib/extend/deployer.ts | 6 +- lib/extend/filter.ts | 6 +- lib/extend/generator.ts | 6 +- lib/extend/helper.ts | 2 +- lib/extend/injector.ts | 14 ++--- lib/extend/migrator.ts | 6 +- lib/extend/processor.ts | 4 +- lib/extend/renderer.ts | 48 ++++++++-------- lib/extend/syntax_highlight.ts | 6 +- lib/extend/tag.ts | 20 +++---- lib/hexo/index.ts | 29 +++++----- lib/hexo/load_config.ts | 5 +- lib/hexo/load_database.ts | 3 +- lib/hexo/load_plugins.ts | 13 +++-- lib/hexo/load_theme_config.ts | 5 +- lib/hexo/locals.ts | 6 +- lib/hexo/multi_config_path.ts | 5 +- lib/hexo/post.ts | 54 ++++++++++-------- lib/hexo/register_models.ts | 3 +- lib/hexo/render.ts | 27 +++++---- lib/hexo/router.ts | 8 +-- lib/hexo/scaffold.ts | 16 +++--- lib/hexo/source.ts | 3 +- lib/hexo/update_package.ts | 5 +- lib/hexo/validate_config.ts | 4 +- lib/models/asset.ts | 3 +- lib/models/cache.ts | 3 +- lib/models/category.ts | 3 +- lib/models/data.ts | 3 +- lib/models/page.ts | 3 +- lib/models/post.ts | 3 +- lib/models/post_asset.ts | 3 +- lib/models/post_category.ts | 3 +- lib/models/post_tag.ts | 3 +- lib/models/tag.ts | 3 +- lib/plugins/console/clean.ts | 7 ++- lib/plugins/console/config.ts | 9 +-- lib/plugins/console/deploy.ts | 3 +- lib/plugins/console/generate.ts | 19 ++++--- lib/plugins/console/list/category.ts | 3 +- lib/plugins/console/list/common.ts | 2 +- lib/plugins/console/list/index.ts | 3 +- lib/plugins/console/list/page.ts | 3 +- lib/plugins/console/list/post.ts | 3 +- lib/plugins/console/list/route.ts | 3 +- lib/plugins/console/list/tag.ts | 3 +- lib/plugins/console/migrate.ts | 3 +- lib/plugins/console/new.ts | 3 +- lib/plugins/console/publish.ts | 3 +- lib/plugins/console/render.ts | 3 +- .../filter/after_post_render/excerpt.ts | 2 +- .../filter/after_post_render/external_link.ts | 5 +- lib/plugins/filter/after_post_render/index.ts | 4 +- .../filter/after_render/external_link.ts | 5 +- lib/plugins/filter/after_render/index.ts | 4 +- .../filter/after_render/meta_generator.ts | 4 +- lib/plugins/filter/before_exit/index.ts | 4 +- .../filter/before_exit/save_database.ts | 4 +- lib/plugins/filter/before_generate/index.ts | 4 +- .../filter/before_generate/render_post.ts | 3 +- .../before_post_render/backtick_code_block.ts | 6 +- .../filter/before_post_render/index.ts | 4 +- .../filter/before_post_render/titlecase.ts | 2 +- lib/plugins/filter/new_post_path.ts | 3 +- lib/plugins/filter/post_permalink.ts | 3 +- lib/plugins/filter/template_locals/i18n.ts | 3 +- lib/plugins/filter/template_locals/index.ts | 4 +- lib/plugins/generator/asset.ts | 5 +- lib/plugins/helper/css.ts | 2 +- lib/plugins/helper/date.ts | 23 ++++---- lib/plugins/helper/debug.ts | 4 +- lib/plugins/helper/favicon_tag.ts | 2 +- lib/plugins/helper/feed_tag.ts | 4 +- lib/plugins/helper/format.ts | 2 +- lib/plugins/helper/fragment_cache.ts | 4 +- lib/plugins/helper/full_url_for.ts | 2 +- lib/plugins/helper/js.ts | 2 +- lib/plugins/helper/list_categories.ts | 2 +- lib/plugins/helper/mail_to.ts | 2 +- lib/plugins/helper/markdown.ts | 2 +- lib/plugins/helper/open_graph.ts | 4 +- lib/plugins/helper/paginator.ts | 56 ++++++++++--------- lib/plugins/helper/partial.ts | 3 +- lib/plugins/helper/relative_url.ts | 2 +- lib/plugins/helper/render.ts | 4 +- lib/plugins/helper/toc.ts | 2 +- lib/plugins/helper/url_for.ts | 6 +- lib/plugins/processor/asset.ts | 13 +++-- lib/plugins/processor/common.ts | 12 ++-- lib/plugins/processor/data.ts | 6 +- lib/plugins/processor/post.ts | 17 +++--- lib/plugins/renderer/json.ts | 4 +- lib/plugins/renderer/nunjucks.ts | 15 ++--- lib/plugins/renderer/plain.ts | 4 +- lib/plugins/renderer/yaml.ts | 3 +- lib/plugins/tag/asset_img.ts | 5 +- lib/plugins/tag/asset_link.ts | 5 +- lib/plugins/tag/asset_path.ts | 5 +- lib/plugins/tag/blockquote.ts | 5 +- lib/plugins/tag/code.ts | 30 ++++------ lib/plugins/tag/full_url_for.ts | 3 +- lib/plugins/tag/iframe.ts | 2 +- lib/plugins/tag/img.ts | 5 +- lib/plugins/tag/include_code.ts | 3 +- lib/plugins/tag/index.ts | 4 +- lib/plugins/tag/link.ts | 2 +- lib/plugins/tag/post_link.ts | 5 +- lib/plugins/tag/post_path.ts | 5 +- lib/plugins/tag/pullquote.ts | 4 +- lib/plugins/tag/url_for.ts | 3 +- lib/theme/index.ts | 12 ++-- lib/theme/processors/config.ts | 8 ++- lib/theme/processors/i18n.ts | 6 +- lib/theme/processors/source.ts | 3 +- lib/theme/processors/view.ts | 8 ++- lib/theme/view.ts | 18 +++--- lib/types.ts | 1 + package.json | 3 +- test/scripts/box/box.js | 2 +- test/scripts/box/file.js | 2 +- test/scripts/extend/renderer.js | 2 +- 124 files changed, 509 insertions(+), 394 deletions(-) create mode 100644 lib/types.ts diff --git a/lib/box/file.ts b/lib/box/file.ts index 6171e430d6..99bb509ddd 100644 --- a/lib/box/file.ts +++ b/lib/box/file.ts @@ -1,10 +1,12 @@ -import { readFile, readFileSync, stat, statSync } from 'hexo-fs'; +import type Promise from 'bluebird'; +import { readFile, readFileSync, stat, statSync, type ReadFileOptions } from 'hexo-fs'; +import type fs from 'fs'; class File { - public source: any; - public path: any; + public source: string; + public path: string; public params: any; - public type: any; + public type: string; static TYPE_CREATE: 'create'; static TYPE_UPDATE: 'update'; static TYPE_SKIP: 'skip'; @@ -17,19 +19,19 @@ class File { this.type = type; } - read(options) { + read(options?: ReadFileOptions): Promise { return readFile(this.source, options); } - readSync(options) { + readSync(options?: ReadFileOptions): string | Buffer { return readFileSync(this.source, options); } - stat(options) { + stat(): Promise { return stat(this.source); } - statSync(options) { + statSync(): fs.Stats { return statSync(this.source); } } diff --git a/lib/box/index.ts b/lib/box/index.ts index a61e08e54e..3222b55880 100644 --- a/lib/box/index.ts +++ b/lib/box/index.ts @@ -6,6 +6,7 @@ import { createReadStream, readdir, stat, watch } from 'hexo-fs'; import { magenta } from 'picocolors'; import { EventEmitter } from 'events'; import { isMatch, makeRe } from 'micromatch'; +import type Hexo from '../hexo'; const defaultPattern = new Pattern(() => ({})); @@ -16,20 +17,18 @@ interface Processor { class Box extends EventEmitter { public options: any; - public context: any; - public base: any; + public context: Hexo; + public base: string; public processors: Processor[]; public _processingFiles: any; public watcher: any; public Cache: any; // TODO: replace runtime class _File public File: any; - public ignore: any; + public ignore: any[]; public source: any; - public emit: any; - public ctx: any; - constructor(ctx, base, options?: object) { + constructor(ctx: Hexo, base: string, options?: object) { super(); this.options = Object.assign({ @@ -64,13 +63,13 @@ class Box extends EventEmitter { class _File extends File { public box: Box; - render(options) { + render(options?: object) { return ctx.render.render({ path: this.source }, options); } - renderSync(options) { + renderSync(options?: object) { return ctx.render.renderSync({ path: this.source }, options); @@ -82,7 +81,9 @@ class Box extends EventEmitter { return _File; } - addProcessor(pattern, fn) { + 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 { if (!fn && typeof pattern === 'function') { fn = pattern; pattern = defaultPattern; @@ -97,7 +98,7 @@ class Box extends EventEmitter { }); } - _readDir(base, prefix = '') { + _readDir(base: string, prefix = ''): BlueBirdPromise { const { context: ctx } = this; const results = []; return readDirWalker(ctx, base, results, this.ignore, prefix) @@ -106,7 +107,7 @@ class Box extends EventEmitter { .map(file => this._processFile(file.type, file.path).return(file.path)); } - _checkFileStatus(path) { + _checkFileStatus(path: string) { const { Cache, context: ctx } = this; const src = join(this.base, path); @@ -120,7 +121,7 @@ class Box extends EventEmitter { })); } - process(callback?) { + process(callback?: NodeJSLikeCallback): BlueBirdPromise { const { base, Cache, context: ctx } = this; return stat(base).then(stats => { @@ -132,14 +133,14 @@ class Box extends EventEmitter { // Handle deleted files return this._readDir(base) - .then(files => cacheFiles.filter(path => !files.includes(path))) - .map(path => this._processFile(File.TYPE_DELETE, path)); + .then((files: string[]) => cacheFiles.filter((path: string) => !files.includes(path))) + .map((path: string) => this._processFile(File.TYPE_DELETE, path) as PromiseLike); }).catch(err => { if (err && err.code !== 'ENOENT') throw err; }).asCallback(callback); } - _processFile(type, path) { + _processFile(type: string, path: string): BlueBirdPromise | BlueBirdPromise { if (this._processingFiles[path]) { return BlueBirdPromise.resolve(); } @@ -182,7 +183,7 @@ class Box extends EventEmitter { }).thenReturn(path); } - watch(callback?) { + watch(callback?: NodeJSLikeCallback): BlueBirdPromise { if (this.isWatching()) { return BlueBirdPromise.reject(new Error('Watcher has already started.')).asCallback(callback); } @@ -217,24 +218,24 @@ class Box extends EventEmitter { }).asCallback(callback); } - unwatch() { + unwatch(): void { if (!this.isWatching()) return; this.watcher.close(); this.watcher = null; } - isWatching() { + isWatching(): boolean { return Boolean(this.watcher); } } -function escapeBackslash(path) { +function escapeBackslash(path: string): string { // Replace backslashes on Windows return path.replace(/\\/g, '/'); } -function getHash(path) { +function getHash(path: string): BlueBirdPromise { const src = createReadStream(path); const hasher = createSha1Hash(); @@ -248,7 +249,7 @@ function getHash(path) { return finishedPromise.then(() => hasher.digest('hex')); } -function toRegExp(ctx, arg) { +function toRegExp(ctx: Hexo, arg: string): RegExp | null { if (!arg) return null; if (typeof arg !== 'string') { ctx.log.warn('A value of "ignore:" section in "_config.yml" is not invalid (not a string)'); @@ -262,11 +263,11 @@ function toRegExp(ctx, arg) { return result; } -function isIgnoreMatch(path, ignore) { +function isIgnoreMatch(path: string, ignore: string | any[]): boolean { return path && ignore && ignore.length && isMatch(path, ignore); } -function readDirWalker(ctx, base, results, ignore, prefix) { +function readDirWalker(ctx: Hexo, base: string, results: any[], ignore: any, prefix: string): BlueBirdPromise { if (isIgnoreMatch(base, ignore)) return BlueBirdPromise.resolve(); return BlueBirdPromise.map(readdir(base).catch(err => { @@ -292,4 +293,10 @@ function readDirWalker(ctx, base, results, ignore, prefix) { }); } -export = Box; +export interface _File extends File { + box: Box; + render(options?: any): any; + renderSync(options?: any): any; +} + +export default Box; diff --git a/lib/extend/console.ts b/lib/extend/console.ts index c4af6322d7..a5b7868af9 100644 --- a/lib/extend/console.ts +++ b/lib/extend/console.ts @@ -51,7 +51,7 @@ class Console { return this.store[this.alias[name]]; } - list() { + list(): Store { return this.store; } @@ -66,7 +66,7 @@ class Console { register(name: string, desc: string, fn: AnyFn): void register(name: string, options: Option, fn: AnyFn): void register(name: string, desc: string, options: Option, fn: AnyFn): void - register(name: string, desc: string | Option | AnyFn, options?: Option | AnyFn, fn?: AnyFn) { + register(name: string, desc: string | Option | AnyFn, options?: Option | AnyFn, fn?: AnyFn): void { if (!name) throw new TypeError('name is required'); if (!fn) { diff --git a/lib/extend/deployer.ts b/lib/extend/deployer.ts index d42d3d854c..ae88664cdc 100644 --- a/lib/extend/deployer.ts +++ b/lib/extend/deployer.ts @@ -17,15 +17,15 @@ class Deployer { this.store = {}; } - list() { + list(): Store { return this.store; } - get(name: string) { + get(name: string): StoreFunction { return this.store[name]; } - register(name: string, fn: StoreFunction) { + register(name: string, fn: StoreFunction): 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/filter.ts b/lib/extend/filter.ts index 78113d01c2..2af06fae87 100644 --- a/lib/extend/filter.ts +++ b/lib/extend/filter.ts @@ -38,7 +38,7 @@ class Filter { register(fn: StoreFunction, priority: number): void register(type: string, fn: StoreFunction): void register(type: string, fn: StoreFunction, priority: number): void - register(type: string | StoreFunction, fn?: StoreFunction | number, priority?: number) { + register(type: string | StoreFunction, fn?: StoreFunction | number, priority?: number): void { if (!priority) { if (typeof type === 'function') { priority = fn as number; @@ -61,7 +61,7 @@ class Filter { store.sort((a, b) => a.priority - b.priority); } - unregister(type: string, fn: StoreFunction) { + unregister(type: string, fn: StoreFunction): void { if (!type) throw new TypeError('type is required'); if (typeof fn !== 'function') throw new TypeError('fn must be a function'); @@ -75,7 +75,7 @@ class Filter { if (index !== -1) list.splice(index, 1); } - exec(type: string, data: any[], options: FilterOptions = {}) { + exec(type: string, data: any[], options: FilterOptions = {}): Promise { const filters = this.list(type); if (filters.length === 0) return Promise.resolve(data); diff --git a/lib/extend/generator.ts b/lib/extend/generator.ts index 6360d1eb2c..2854f8f869 100644 --- a/lib/extend/generator.ts +++ b/lib/extend/generator.ts @@ -31,17 +31,17 @@ class Generator { this.store = {}; } - list() { + list(): Store { return this.store; } - get(name: string) { + get(name: string): StoreFunction { return this.store[name]; } register(fn: GeneratorFunction): void register(name: string, fn: GeneratorFunction): void - register(name: string | GeneratorFunction, fn?: GeneratorFunction) { + register(name: string | GeneratorFunction, fn?: GeneratorFunction): void { if (!fn) { if (typeof name === 'function') { // fn fn = name; diff --git a/lib/extend/helper.ts b/lib/extend/helper.ts index 7903557c97..f167282371 100644 --- a/lib/extend/helper.ts +++ b/lib/extend/helper.ts @@ -35,7 +35,7 @@ class Helper { * @param {String} name - The name of the helper plugin * @param {StoreFunction} fn - The helper plugin function */ - register(name: string, fn: StoreFunction) { + register(name: string, fn: StoreFunction): 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/injector.ts b/lib/extend/injector.ts index fd1d09acdd..edb4a45094 100644 --- a/lib/extend/injector.ts +++ b/lib/extend/injector.ts @@ -24,15 +24,15 @@ class Injector { this.cache = new Cache(); } - list() { + list(): Store { return this.store; } - get(entry: Entry, to = 'default') { + get(entry: Entry, to = 'default'): any[] { return Array.from(this.store[entry][to] || []); } - getText(entry: Entry, to = 'default') { + getText(entry: Entry, to = 'default'): string { const arr = this.get(entry, to); if (!arr || !arr.length) return ''; return arr.join(''); @@ -42,7 +42,7 @@ class Injector { return this.cache.apply(`${entry}-size`, Object.keys(this.store[entry]).length); } - register(entry: Entry, value: string | (() => string), to = 'default') { + register(entry: Entry, value: string | (() => string), to = 'default'): void { if (!entry) throw new TypeError('entry is required'); if (typeof value === 'function') value = value(); @@ -52,7 +52,7 @@ class Injector { entryMap[to] = valueSet; } - _getPageType(pageLocals) { + _getPageType(pageLocals): string { let currentType = 'default'; if (pageLocals.__index) currentType = 'home'; if (pageLocals.__post) currentType = 'post'; @@ -65,7 +65,7 @@ class Injector { return currentType; } - _injector(input, pattern, flag, isBegin = true, currentType) { + _injector(input: string, pattern: string | RegExp, flag: Entry, isBegin = true, currentType: string): string { if (input.includes(`hexo injector ${flag}`)) return input; const code = this.cache.apply(`${flag}-${currentType}-code`, () => { @@ -81,7 +81,7 @@ class Injector { return input.replace(pattern, str => { return isBegin ? str + code : code + str; }); } - exec(data, locals = { page: {} }) { + exec(data: string, locals = { page: {} }): string { const { page } = locals; const currentType = this._getPageType(page); diff --git a/lib/extend/migrator.ts b/lib/extend/migrator.ts index 2a149f191a..5ab0f7063e 100644 --- a/lib/extend/migrator.ts +++ b/lib/extend/migrator.ts @@ -14,15 +14,15 @@ class Migrator { this.store = {}; } - list() { + list(): Store { return this.store; } - get(name: string) { + get(name: string): StoreFunction { return this.store[name]; } - register(name: string, fn: StoreFunction) { + register(name: string, fn: StoreFunction): 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/processor.ts b/lib/extend/processor.ts index 0af6998494..ce73da1031 100644 --- a/lib/extend/processor.ts +++ b/lib/extend/processor.ts @@ -19,13 +19,13 @@ class Processor { this.store = []; } - list() { + list(): Store { return this.store; } register(fn: StoreFunction): void; register(pattern: patternType, fn: StoreFunction): void; - register(pattern: patternType | StoreFunction, fn?: StoreFunction) { + register(pattern: patternType | StoreFunction, fn?: StoreFunction): void { if (!fn) { if (typeof pattern === 'function') { fn = pattern; diff --git a/lib/extend/renderer.ts b/lib/extend/renderer.ts index c70e054f18..15f90c6de6 100644 --- a/lib/extend/renderer.ts +++ b/lib/extend/renderer.ts @@ -8,36 +8,36 @@ const getExtname = (str: string) => { return ext.startsWith('.') ? ext.slice(1) : ext; }; -interface StoreSyncFunction { +export interface StoreFunctionData { + path?: any; + text?: string; + engine?: string; + toString?: any; + onRenderEnd?: any; +} + +export interface StoreSyncFunction { + [x: string]: any; ( - data: { - path?: string; - text: string; - }, + data: StoreFunctionData, options: object, - // callback: (err: Error, value: string) => any + // callback: NodeJSLikeCallback ): any; output?: string; - compile?: (local: object) => string; + compile?: (local: object) => any; } -interface StoreFunction { +export interface StoreFunction { ( - data: { - path?: string; - text: string; - }, + data: StoreFunctionData, options: object, ): Promise; ( - data: { - path?: string; - text: string; - }, + data: StoreFunctionData, options: object, - callback: (err: Error, value: string) => any + callback: NodeJSLikeCallback ): void; output?: string; - compile?: (local: object) => string; + compile?: (local: object) => any; disableNunjucks?: boolean; } @@ -57,25 +57,25 @@ class Renderer { this.storeSync = {}; } - list(sync: boolean) { + list(sync: boolean): Store | SyncStore { return sync ? this.storeSync : this.store; } - get(name: string, sync?: boolean) { + get(name: string, sync?: boolean): StoreSyncFunction | StoreFunction { const store = this[sync ? 'storeSync' : 'store']; return store[getExtname(name)] || store[name]; } - isRenderable(path: string) { + isRenderable(path: string): boolean { return Boolean(this.get(path)); } - isRenderableSync(path: string) { + isRenderableSync(path: string): boolean { return Boolean(this.get(path, true)); } - getOutput(path: string) { + getOutput(path: string): string { const renderer = this.get(path); return renderer ? renderer.output : ''; } @@ -109,4 +109,4 @@ class Renderer { } } -export = Renderer; +export default Renderer; diff --git a/lib/extend/syntax_highlight.ts b/lib/extend/syntax_highlight.ts index 419a950f24..c5cf28a95f 100644 --- a/lib/extend/syntax_highlight.ts +++ b/lib/extend/syntax_highlight.ts @@ -3,7 +3,7 @@ import type Hexo from '../hexo'; export interface HighlightOptions { lang: string | undefined, caption: string | undefined, - lines_length: number, + lines_length?: number | undefined, // plugins/filter/before_post_render/backtick_code_block firstLineNumber?: string | number @@ -39,13 +39,13 @@ class SyntaxHighlight { this.store = {}; } - register(name: string, fn: StoreFunction) { + register(name: string, fn: StoreFunction): void { if (typeof fn !== 'function') throw new TypeError('fn must be a function'); this.store[name] = fn; } - query(name: string) { + query(name: string): StoreFunction { return name && this.store[name]; } diff --git a/lib/extend/tag.ts b/lib/extend/tag.ts index f2fcc3d325..d44b5dd993 100644 --- a/lib/extend/tag.ts +++ b/lib/extend/tag.ts @@ -4,7 +4,7 @@ import { Environment } from 'nunjucks'; import Promise from 'bluebird'; const rSwigRawFullBlock = /{% *raw *%}/; const rCodeTag = /]*>[\s\S]+?<\/code>/g; -const escapeSwigTag = str => str.replace(/{/g, '{').replace(/}/g, '}'); +const escapeSwigTag = (str: string) => str.replace(/{/g, '{').replace(/}/g, '}'); interface TagFunction { (args: any[], content: string): string; @@ -66,7 +66,7 @@ class NunjucksTag { } } -const trimBody = body => { +const trimBody = (body: () => any) => { return stripIndent(body()).replace(/^\n?|\n?$/g, ''); }; @@ -126,7 +126,7 @@ class NunjucksAsyncBlock extends NunjucksBlock { } } -const getContextLineNums = (min, max, center, amplitude) => { +const getContextLineNums = (min: number, max: number, center: number, amplitude: number) => { const result = []; let lbound = Math.max(min, center - amplitude); const hbound = Math.min(max, center + amplitude); @@ -136,7 +136,7 @@ const getContextLineNums = (min, max, center, amplitude) => { const LINES_OF_CONTEXT = 5; -const getContext = (lines, errLine, location, type) => { +const getContext = (lines: string[], errLine: number, location: string, type: string) => { const message = [ location + ' ' + red(type), cyan(' ===== Context Dump ====='), @@ -173,7 +173,7 @@ class NunjucksError extends Error { * @param {string} str string input for Nunjucks * @return {Error} New error object with embedded context */ -const formatNunjucksError = (err, input, source = '') => { +const formatNunjucksError = (err: Error, input: string, source = ''): Error => { err.message = err.message.replace('(unknown path)', source ? magenta(source) : ''); const match = err.message.match(/Line (\d+), Column \d+/); @@ -199,8 +199,8 @@ type RegisterOptions = { } class Tag { - public env: any; - public source: any; + public env: Environment; + public source: string; constructor() { this.env = new Environment(null, { @@ -211,7 +211,7 @@ class Tag { register(name: string, fn: TagFunction): void register(name: string, fn: TagFunction, ends: boolean): void register(name: string, fn: TagFunction, options: RegisterOptions): void - register(name: string, fn: TagFunction, options?: RegisterOptions | boolean) { + register(name: string, fn: TagFunction, options?: RegisterOptions | boolean):void { if (!name) throw new TypeError('name is required'); if (typeof fn !== 'function') throw new TypeError('fn must be a function'); @@ -243,7 +243,7 @@ class Tag { this.env.addExtension(name, tag); } - unregister(name) { + unregister(name: string): void { if (!name) throw new TypeError('name is required'); const { env } = this; @@ -251,7 +251,7 @@ class Tag { if (env.hasExtension(name)) env.removeExtension(name); } - render(str, options: { source?: string } = {}, callback) { + render(str: string, options: { source?: string } = {}, callback?: NodeJSLikeCallback): Promise { if (!callback && typeof options === 'function') { callback = options; options = {}; diff --git a/lib/hexo/index.ts b/lib/hexo/index.ts index 2d347c7bde..c248b7b675 100644 --- a/lib/hexo/index.ts +++ b/lib/hexo/index.ts @@ -36,16 +36,17 @@ import defaultConfig from './default_config'; import loadDatabase from './load_database'; import multiConfigPath from './multi_config_path'; import { deepMerge, full_url_for } from 'hexo-util'; +import type Box from '../box'; let resolveSync; // = require('resolve'); const libDir = dirname(__dirname); const dbVersion = 1; -const stopWatcher = box => { if (box.isWatching()) box.unwatch(); }; +const stopWatcher = (box: Box) => { if (box.isWatching()) box.unwatch(); }; const routeCache = new WeakMap(); -const castArray = obj => { return Array.isArray(obj) ? obj : [obj]; }; +const castArray = (obj: any) => { return Array.isArray(obj) ? obj : [obj]; }; const mergeCtxThemeConfig = ctx => { // Merge hexo.config.theme_config into hexo.theme.config before post rendering & generating @@ -335,7 +336,7 @@ class Hexo extends EventEmitter { }); } - call(name, args, callback) { + call(name: string, args: any, callback?: NodeJSLikeCallback) { if (!callback && typeof args === 'function') { callback = args; args = {}; @@ -348,11 +349,11 @@ class Hexo extends EventEmitter { return Promise.reject(new Error(`Console \`${name}\` has not been registered yet!`)); } - model(name, schema) { + model(name: string, schema?: any) { return this.database.model(name, schema); } - resolvePlugin(name, basedir) { + resolvePlugin(name: string, basedir: string) { try { // Try to resolve the plugin with the Node.js's built-in require.resolve. return require.resolve(name, { paths: [basedir] }); @@ -370,18 +371,18 @@ class Hexo extends EventEmitter { } } - loadPlugin(path: string, callback: (...args: any[]) => any) { + loadPlugin(path: string, callback?: NodeJSLikeCallback) { return readFile(path).then(script => { // Based on: https://github.com/joyent/node/blob/v0.10.33/src/node.js#L516 const module = new Module(path); module.filename = path; module.paths = Module._nodeModulePaths(path); - function req(path) { + function req(path: string) { return module.require(path); } - req.resolve = request => Module._resolveFilename(request, module); + req.resolve = (request: string) => Module._resolveFilename(request, module); req.main = require.main; req.extensions = Module._extensions; @@ -400,7 +401,7 @@ class Hexo extends EventEmitter { return args.draft || args.drafts || this.config.render_drafts; } - load(callback) { + load(callback?: NodeJSLikeCallback) { return loadDatabase(this).then(() => { this.log.info('Start processing'); @@ -414,7 +415,7 @@ class Hexo extends EventEmitter { }).asCallback(callback); } - watch(callback) { + watch(callback?: NodeJSLikeCallback) { let useCache = false; const { cache } = Object.assign({ cache: false @@ -478,7 +479,7 @@ class Hexo extends EventEmitter { site: object; cache?: boolean; - constructor(path, locals) { + constructor(path: string, locals) { this.page = { ...locals }; if (this.page.path == null) this.page.path = path; this.path = path; @@ -512,7 +513,7 @@ class Hexo extends EventEmitter { }, []); } - _routerRefresh(runningGenerators, useCache) { + _routerRefresh(runningGenerators: Promise, useCache: boolean) { const { route } = this; const routeList = route.list(); const Locals = this._generateLocals(); @@ -580,11 +581,11 @@ class Hexo extends EventEmitter { }); } - execFilter(type, data, options) { + execFilter(type: string, data: any, options) { return this.extend.filter.exec(type, data, options); } - execFilterSync(type, data, options) { + execFilterSync(type: string, data: any, options) { return this.extend.filter.execSync(type, data, options); } } diff --git a/lib/hexo/load_config.ts b/lib/hexo/load_config.ts index 231e285f02..489f4e03ff 100644 --- a/lib/hexo/load_config.ts +++ b/lib/hexo/load_config.ts @@ -6,8 +6,9 @@ import { exists, readdir } from 'hexo-fs'; import { magenta } from 'picocolors'; import { deepMerge } from 'hexo-util'; import validateConfig from './validate_config'; +import type Hexo from './index'; -export = async ctx => { +export = async (ctx: Hexo) => { if (!ctx.env.init) return; const baseDir = ctx.base_dir; @@ -65,7 +66,7 @@ export = async ctx => { }; -async function findConfigPath(path) { +async function findConfigPath(path: string) { const { dir, name } = parse(path); const files = await readdir(dir); diff --git a/lib/hexo/load_database.ts b/lib/hexo/load_database.ts index c64719c929..f0ac5decb0 100644 --- a/lib/hexo/load_database.ts +++ b/lib/hexo/load_database.ts @@ -1,7 +1,8 @@ import { exists, unlink } from 'hexo-fs'; import Promise from 'bluebird'; +import type Hexo from './index'; -export = ctx => { +export = (ctx: Hexo) => { if (ctx._dbLoaded) return Promise.resolve(); const db = ctx.database; diff --git a/lib/hexo/load_plugins.ts b/lib/hexo/load_plugins.ts index c1dcb29067..289474f00f 100644 --- a/lib/hexo/load_plugins.ts +++ b/lib/hexo/load_plugins.ts @@ -2,14 +2,15 @@ import { join } from 'path'; import { exists, readFile, listDir } from 'hexo-fs'; import Promise from 'bluebird'; import { magenta } from 'picocolors'; +import type Hexo from './index'; -export = ctx => { +export = (ctx: Hexo) => { if (!ctx.env.init || ctx.env.safe) return; return loadModules(ctx).then(() => loadScripts(ctx)); }; -function loadModuleList(ctx, basedir) { +function loadModuleList(ctx: Hexo, basedir: string) { const packagePath = join(basedir, 'package.json'); // Make sure package.json exists @@ -42,14 +43,14 @@ function loadModuleList(ctx, basedir) { }); } -function loadModules(ctx) { +function loadModules(ctx: Hexo) { return Promise.map([ctx.base_dir, ctx.theme_dir], basedir => loadModuleList(ctx, basedir)) .then(([hexoModuleList, themeModuleList]) => { return Object.entries(Object.assign(themeModuleList, hexoModuleList)); }) .map(([name, path]) => { // Load plugins - return ctx.loadPlugin(path).then(() => { + return ctx.loadPlugin(path as string).then(() => { ctx.log.debug('Plugin loaded: %s', magenta(name)); }).catch(err => { ctx.log.error({err}, 'Plugin load failed: %s', magenta(name)); @@ -57,7 +58,7 @@ function loadModules(ctx) { }); } -function loadScripts(ctx) { +function loadScripts(ctx: Hexo) { const baseDirLength = ctx.base_dir.length; return Promise.filter([ @@ -76,6 +77,6 @@ function loadScripts(ctx) { })); } -function displayPath(path, baseDirLength) { +function displayPath(path: string, baseDirLength: number) { return magenta(path.substring(baseDirLength)); } diff --git a/lib/hexo/load_theme_config.ts b/lib/hexo/load_theme_config.ts index 57a28adb41..54c700960a 100644 --- a/lib/hexo/load_theme_config.ts +++ b/lib/hexo/load_theme_config.ts @@ -3,8 +3,9 @@ import tildify from 'tildify'; import { exists, readdir } from 'hexo-fs'; import { magenta } from 'picocolors'; import { deepMerge } from 'hexo-util'; +import type Hexo from './index'; -export = ctx => { +export = (ctx: Hexo) => { if (!ctx.env.init) return; if (!ctx.config.theme) return; @@ -30,7 +31,7 @@ export = ctx => { }); }; -function findConfigPath(path) { +function findConfigPath(path: string) { const { dir, name } = parse(path); return readdir(dir).then(files => { diff --git a/lib/hexo/locals.ts b/lib/hexo/locals.ts index 468dabe26f..7153cb0a48 100644 --- a/lib/hexo/locals.ts +++ b/lib/hexo/locals.ts @@ -9,7 +9,7 @@ class Locals { this.getters = {}; } - get(name) { + get(name: string) { if (typeof name !== 'string') throw new TypeError('name must be a string!'); return this.cache.apply(name, () => { @@ -20,7 +20,7 @@ class Locals { }); } - set(name, value) { + set(name: string, value: any) { if (typeof name !== 'string') throw new TypeError('name must be a string!'); if (value == null) throw new TypeError('value is required!'); @@ -32,7 +32,7 @@ class Locals { return this; } - remove(name) { + remove(name: string) { if (typeof name !== 'string') throw new TypeError('name must be a string!'); this.getters[name] = null; diff --git a/lib/hexo/multi_config_path.ts b/lib/hexo/multi_config_path.ts index 8d140d3569..978c04fca0 100644 --- a/lib/hexo/multi_config_path.ts +++ b/lib/hexo/multi_config_path.ts @@ -2,8 +2,9 @@ import { isAbsolute, resolve, join, extname } from 'path'; import { existsSync, readFileSync, writeFileSync } from 'hexo-fs'; import yml from 'js-yaml'; import { deepMerge } from 'hexo-util'; +import type Hexo from './index'; -export = ctx => function multiConfigPath(base, configPaths, outputDir) { +export = (ctx: Hexo) => function multiConfigPath(base: string, configPaths: string, outputDir: string) { const { log } = ctx; const defaultPath = join(base, '_config.yml'); @@ -12,7 +13,7 @@ export = ctx => function multiConfigPath(base, configPaths, outputDir) { return join(base, '_config.yml'); } - let paths; + let paths: string[]; // determine if comma or space separated if (configPaths.includes(',')) { paths = configPaths.replace(' ', '').split(','); diff --git a/lib/hexo/post.ts b/lib/hexo/post.ts index 748d73fd94..f9269484e2 100644 --- a/lib/hexo/post.ts +++ b/lib/hexo/post.ts @@ -7,6 +7,7 @@ import { load } from 'js-yaml'; import { slugize, escapeRegExp } from 'hexo-util'; import { copyDir, exists, listDir, mkdirs, readFile, rmdir, unlink, writeFile } from 'hexo-fs'; import { parse as yfmParse, split as yfmSplit, stringify as yfmStringify } from 'hexo-front-matter'; +import type Hexo from './index'; const preservedKeys = ['title', 'slug', 'path', 'layout', 'date', 'content']; const rHexoPostRenderEscape = /([\s\S]+?)<\/hexoPostRenderCodeBlock>/g; @@ -20,7 +21,7 @@ const STATE_SWIG_COMMENT = Symbol('swig_comment'); const STATE_SWIG_TAG = Symbol('swig_tag'); const STATE_SWIG_FULL_TAG = Symbol('swig_full_tag'); -const isNonWhiteSpaceChar = char => char !== '\r' +const isNonWhiteSpaceChar = (char: string) => char !== '\r' && char !== '\n' && char !== '\t' && char !== '\f' @@ -28,18 +29,18 @@ const isNonWhiteSpaceChar = char => char !== '\r' && char !== ' '; class PostRenderEscape { - public stored: any; - public length: any; + public stored: any[]; + public length: number; constructor() { this.stored = []; } - static escapeContent(cache, flag, str) { + static escapeContent(cache: any[], flag: string, str: string) { return ``; } - static restoreContent(cache) { + static restoreContent(cache: any[]) { return (_, index) => { assert(cache[index]); const value = cache[index]; @@ -48,16 +49,16 @@ class PostRenderEscape { }; } - restoreAllSwigTags(str) { + restoreAllSwigTags(str: string) { const restored = str.replace(rSwigPlaceHolder, PostRenderEscape.restoreContent(this.stored)); return restored; } - restoreCodeBlocks(str) { + restoreCodeBlocks(str: string) { return str.replace(rCodeBlockPlaceHolder, PostRenderEscape.restoreContent(this.stored)); } - escapeCodeBlocks(str) { + escapeCodeBlocks(str: string) { return str.replace(rHexoPostRenderEscape, (_, content) => PostRenderEscape.escapeContent(this.stored, 'code', content)); } @@ -65,7 +66,7 @@ class PostRenderEscape { * @param {string} str * @returns string */ - escapeAllSwigTags(str) { + escapeAllSwigTags(str: string) { let state = STATE_PLAINTEXT; let buffer = ''; let output = ''; @@ -185,7 +186,7 @@ class PostRenderEscape { } } -const prepareFrontMatter = (data, jsonMode) => { +const prepareFrontMatter = (data: any, jsonMode: boolean) => { for (const [key, item] of Object.entries(data)) { if (moment.isMoment(item)) { data[key] = item.utc().format('YYYY-MM-DD HH:mm:ss'); @@ -202,11 +203,11 @@ const prepareFrontMatter = (data, jsonMode) => { }; -const removeExtname = str => { +const removeExtname = (str: string) => { return str.substring(0, str.length - extname(str).length); }; -const createAssetFolder = (path, assetFolder) => { +const createAssetFolder = (path: string, assetFolder: boolean) => { if (!assetFolder) return Promise.resolve(); const target = removeExtname(path); @@ -231,17 +232,24 @@ interface Data { source?: string; } +interface PostData { + title?: string; + layout?: string; + slug?: string; + path?: string; + [prop: string]: any; +} + class Post { - public context: any; - public config: any; - public tag: any; - public separator: any; + public context: Hexo; - constructor(context) { + constructor(context: Hexo) { this.context = context; } - create(data, replace, callback?) { + create(data: PostData, callback?: NodeJSLikeCallback); + create(data: PostData, replace: boolean, callback?: NodeJSLikeCallback); + create(data: PostData, replace: boolean | (NodeJSLikeCallback), callback?: NodeJSLikeCallback) { if (!callback && typeof replace === 'function') { callback = replace; replace = false; @@ -276,7 +284,7 @@ class Post { }).asCallback(callback); } - _getScaffold(layout) { + _getScaffold(layout: string) { const ctx = this.context; return ctx.scaffold.get(layout).then(result => { @@ -285,7 +293,7 @@ class Post { }); } - _renderScaffold(data) { + _renderScaffold(data: PostData) { const { tag } = this.context.extend; let splitted; @@ -327,7 +335,7 @@ class Post { }); } - publish(data, replace, callback) { + publish(data: PostData, replace: boolean, callback?: NodeJSLikeCallback) { if (!callback && typeof replace === 'function') { callback = replace; replace = false; @@ -354,7 +362,7 @@ class Post { // Read the content src = join(draftDir, item); return readFile(src); - }).then(content => { + }).then((content: string) => { // Create post Object.assign(data, yfmParse(content)); data.content = data._content; @@ -380,7 +388,7 @@ class Post { }).thenReturn(result).asCallback(callback); } - render(source, data: Data = {}, callback) { + render(source: string, data: Data = {}, callback?: NodeJSLikeCallback) { const ctx = this.context; const { config } = ctx; const { tag } = ctx.extend; diff --git a/lib/hexo/register_models.ts b/lib/hexo/register_models.ts index 864e4e3631..88a73e6081 100644 --- a/lib/hexo/register_models.ts +++ b/lib/hexo/register_models.ts @@ -1,6 +1,7 @@ import * as models from '../models'; +import type Hexo from './index'; -export = ctx => { +export = (ctx: Hexo) => { const db = ctx.database; const keys = Object.keys(models); diff --git a/lib/hexo/render.ts b/lib/hexo/render.ts index a25d152314..4d1ebda922 100644 --- a/lib/hexo/render.ts +++ b/lib/hexo/render.ts @@ -1,8 +1,11 @@ import { extname } from 'path'; import Promise from 'bluebird'; import { readFile, readFileSync } from 'hexo-fs'; +import type Hexo from './index'; +import type { Renderer } from '../extend'; +import type { StoreFunctionData } from '../extend/renderer'; -const getExtname = str => { +const getExtname = (str: string) => { if (typeof str !== 'string') return ''; const ext = extname(str); @@ -24,35 +27,35 @@ const toString = (result, options) => { }; class Render { - public context: any; - public renderer: any; + public context: Hexo; + public renderer: Renderer; - constructor(ctx) { + constructor(ctx: Hexo) { this.context = ctx; this.renderer = ctx.extend.renderer; } - isRenderable(path) { + isRenderable(path: string) { return this.renderer.isRenderable(path); } - isRenderableSync(path) { + isRenderableSync(path: string) { return this.renderer.isRenderableSync(path); } - getOutput(path) { + getOutput(path: string) { return this.renderer.getOutput(path); } - getRenderer(ext, sync?) { + getRenderer(ext: string, sync?: boolean) { return this.renderer.get(ext, sync); } - getRendererSync(ext) { + getRendererSync(ext: string) { return this.getRenderer(ext, true); } - render(data, options, callback) { + render(data: StoreFunctionData, options?: { highlight?: boolean; }, callback?: undefined) { if (!callback && typeof options === 'function') { callback = options; options = {}; @@ -96,14 +99,14 @@ class Render { }).asCallback(callback); } - renderSync(data, options = {}) { + renderSync(data: StoreFunctionData, options = {}) { if (!data) throw new TypeError('No input file or string!'); const ctx = this.context; if (data.text == null) { if (!data.path) throw new TypeError('No input file or string!'); - data.text = readFileSync(data.path); + data.text = readFileSync(data.path) as string; } if (data.text == null) throw new TypeError('No input file or string!'); diff --git a/lib/hexo/router.ts b/lib/hexo/router.ts index f00824d381..33edb61478 100644 --- a/lib/hexo/router.ts +++ b/lib/hexo/router.ts @@ -18,8 +18,6 @@ class RouteStream extends Readable { public _data: any; public _ended: boolean; public modified: any; - public push: any; - public emit: any; constructor(data: Data) { super({ objectMode: true }); @@ -133,14 +131,14 @@ class Router extends EventEmitter { return new RouteStream(data); } - isModified(path) { + isModified(path: string) { if (typeof path !== 'string') throw new TypeError('path must be a string!'); const data = this.routes[this.format(path)]; return data ? data.modified : false; } - set(path, data) { + set(path: string, data: any) { if (typeof path !== 'string') throw new TypeError('path must be a string!'); if (data == null) throw new TypeError('data is required!'); @@ -175,7 +173,7 @@ class Router extends EventEmitter { return this; } - remove(path) { + remove(path: string) { if (typeof path !== 'string') throw new TypeError('path must be a string!'); path = this.format(path); diff --git a/lib/hexo/scaffold.ts b/lib/hexo/scaffold.ts index 18a1a5ff41..37b6e65e86 100644 --- a/lib/hexo/scaffold.ts +++ b/lib/hexo/scaffold.ts @@ -1,12 +1,12 @@ import { extname, join } from 'path'; import { exists, listDir, readFile, unlink, writeFile } from 'hexo-fs'; - +import type Hexo from './index'; class Scaffold { - public context: any; - public scaffoldDir: any; + public context: Hexo; + public scaffoldDir: string; public defaults: any; - constructor(context) { + constructor(context: Hexo) { this.context = context; this.scaffoldDir = context.scaffold_dir; this.defaults = { @@ -36,11 +36,11 @@ class Scaffold { })); } - _getScaffold(name) { + _getScaffold(name: string) { return this._listDir().then(list => list.find(item => item.name === name)); } - get(name, callback) { + get(name: string, callback?: NodeJSLikeCallback) { return this._getScaffold(name).then(item => { if (item) { return readFile(item.path); @@ -50,7 +50,7 @@ class Scaffold { }).asCallback(callback); } - set(name, content, callback) { + set(name: string, content: any, callback: NodeJSLikeCallback) { const { scaffoldDir } = this; return this._getScaffold(name).then(item => { @@ -61,7 +61,7 @@ class Scaffold { }).asCallback(callback); } - remove(name, callback) { + remove(name: string, callback: NodeJSLikeCallback) { return this._getScaffold(name).then(item => { if (!item) return; diff --git a/lib/hexo/source.ts b/lib/hexo/source.ts index ab4d26bc45..736a41037f 100644 --- a/lib/hexo/source.ts +++ b/lib/hexo/source.ts @@ -1,7 +1,8 @@ import Box from '../box'; +import type Hexo from './index'; class Source extends Box { - constructor(ctx) { + constructor(ctx: Hexo) { super(ctx, ctx.source_dir); this.processors = ctx.extend.processor.list(); diff --git a/lib/hexo/update_package.ts b/lib/hexo/update_package.ts index 03319913e6..4b8f3593bd 100644 --- a/lib/hexo/update_package.ts +++ b/lib/hexo/update_package.ts @@ -1,7 +1,8 @@ import { join } from 'path'; import { writeFile, exists, readFile } from 'hexo-fs'; +import type Hexo from './index'; -export = ctx => { +export = (ctx: Hexo) => { const pkgPath = join(ctx.base_dir, 'package.json'); return readPkg(pkgPath).then(pkg => { @@ -18,7 +19,7 @@ export = ctx => { }); }; -function readPkg(path) { +function readPkg(path: string) { return exists(path).then(exist => { if (!exist) return; diff --git a/lib/hexo/validate_config.ts b/lib/hexo/validate_config.ts index 8dfcb389e9..66af8ceeba 100644 --- a/lib/hexo/validate_config.ts +++ b/lib/hexo/validate_config.ts @@ -1,4 +1,6 @@ -export = ctx => { +import type Hexo from './index'; + +export = (ctx: Hexo) => { const { config, log } = ctx; log.info('Validating config'); diff --git a/lib/models/asset.ts b/lib/models/asset.ts index 006391d3b5..5a761192da 100644 --- a/lib/models/asset.ts +++ b/lib/models/asset.ts @@ -1,7 +1,8 @@ import warehouse from 'warehouse'; import { join } from 'path'; +import type Hexo from '../hexo'; -export = ctx => { +export = (ctx: Hexo) => { const Asset = new warehouse.Schema({ _id: {type: String, required: true}, path: {type: String, required: true}, diff --git a/lib/models/cache.ts b/lib/models/cache.ts index d4b43f4722..60db5ce1c4 100644 --- a/lib/models/cache.ts +++ b/lib/models/cache.ts @@ -1,7 +1,8 @@ import warehouse from 'warehouse'; import Promise from 'bluebird'; +import type Hexo from '../hexo'; -export = ctx => { +export = (ctx: Hexo) => { const Cache = new warehouse.Schema({ _id: {type: String, required: true}, hash: {type: String, default: ''}, diff --git a/lib/models/category.ts b/lib/models/category.ts index 740bc67015..2fdbfb58df 100644 --- a/lib/models/category.ts +++ b/lib/models/category.ts @@ -1,7 +1,8 @@ import warehouse from 'warehouse'; import { slugize, full_url_for } from 'hexo-util'; +import type Hexo from '../hexo'; -export = ctx => { +export = (ctx: Hexo) => { const Category = new warehouse.Schema({ name: {type: String, required: true}, parent: { type: warehouse.Schema.Types.CUID, ref: 'Category'} diff --git a/lib/models/data.ts b/lib/models/data.ts index 0cdefe318a..89832d3cf0 100644 --- a/lib/models/data.ts +++ b/lib/models/data.ts @@ -1,6 +1,7 @@ import warehouse from 'warehouse'; +import type Hexo from '../hexo'; -export = ctx => { +export = (ctx: Hexo) => { const Data = new warehouse.Schema({ _id: {type: String, required: true}, data: Object diff --git a/lib/models/page.ts b/lib/models/page.ts index bbaa606422..f1a96922d7 100644 --- a/lib/models/page.ts +++ b/lib/models/page.ts @@ -3,8 +3,9 @@ import { join } from 'path'; import Moment from './types/moment'; import moment from 'moment'; import { full_url_for } from 'hexo-util'; +import type Hexo from '../hexo'; -export = ctx => { +export = (ctx: Hexo) => { const Page = new warehouse.Schema({ title: {type: String, default: ''}, date: { diff --git a/lib/models/post.ts b/lib/models/post.ts index 10b274d7ad..208e8ea477 100644 --- a/lib/models/post.ts +++ b/lib/models/post.ts @@ -4,6 +4,7 @@ import { extname, join, sep } from 'path'; import Promise from 'bluebird'; import Moment from './types/moment'; import { full_url_for, Cache } from 'hexo-util'; +import type Hexo from '../hexo'; function pickID(data) { return data._id; @@ -15,7 +16,7 @@ function removeEmptyTag(tags) { const tagsGetterCache = new Cache(); -export = ctx => { +export = (ctx: Hexo) => { const Post = new warehouse.Schema({ id: String, title: {type: String, default: ''}, diff --git a/lib/models/post_asset.ts b/lib/models/post_asset.ts index 72ec5f90f1..fe73a02a47 100644 --- a/lib/models/post_asset.ts +++ b/lib/models/post_asset.ts @@ -1,7 +1,8 @@ import warehouse from 'warehouse'; import { join } from 'path'; +import type Hexo from '../hexo'; -export = ctx => { +export = (ctx: Hexo) => { const PostAsset = new warehouse.Schema({ _id: {type: String, required: true}, slug: {type: String, required: true}, diff --git a/lib/models/post_category.ts b/lib/models/post_category.ts index f3c813f8be..8b8feb0c0a 100644 --- a/lib/models/post_category.ts +++ b/lib/models/post_category.ts @@ -1,6 +1,7 @@ import warehouse from 'warehouse'; +import type Hexo from '../hexo'; -export = ctx => { +export = (ctx: Hexo) => { const PostCategory = new warehouse.Schema({ post_id: {type: warehouse.Schema.Types.CUID, ref: 'Post'}, category_id: {type: warehouse.Schema.Types.CUID, ref: 'Category'} diff --git a/lib/models/post_tag.ts b/lib/models/post_tag.ts index e727ca5e3e..b55533c49a 100644 --- a/lib/models/post_tag.ts +++ b/lib/models/post_tag.ts @@ -1,6 +1,7 @@ import warehouse from 'warehouse'; +import type Hexo from '../hexo'; -export = ctx => { +export = (ctx: Hexo) => { const PostTag = new warehouse.Schema({ post_id: {type: warehouse.Schema.Types.CUID, ref: 'Post'}, tag_id: {type: warehouse.Schema.Types.CUID, ref: 'Tag'} diff --git a/lib/models/tag.ts b/lib/models/tag.ts index 9c5b10a55e..84a118aa25 100644 --- a/lib/models/tag.ts +++ b/lib/models/tag.ts @@ -1,8 +1,9 @@ import warehouse from 'warehouse'; import { slugize, full_url_for } from 'hexo-util'; const { hasOwnProperty: hasOwn } = Object.prototype; +import type Hexo from '../hexo'; -export = ctx => { +export = (ctx: Hexo) => { const Tag = new warehouse.Schema({ name: {type: String, required: true} }); diff --git a/lib/plugins/console/clean.ts b/lib/plugins/console/clean.ts index fb799039d8..eea456a757 100644 --- a/lib/plugins/console/clean.ts +++ b/lib/plugins/console/clean.ts @@ -1,7 +1,8 @@ import Promise from 'bluebird'; import { exists, unlink, rmdir } from 'hexo-fs'; +import type Hexo from '../../hexo'; -function cleanConsole(args) { +function cleanConsole(this: Hexo): Promise<[void, void, any]> { return Promise.all([ deleteDatabase(this), deletePublicDir(this), @@ -9,7 +10,7 @@ function cleanConsole(args) { ]); } -function deleteDatabase(ctx) { +function deleteDatabase(ctx: Hexo): Promise { const dbPath = ctx.database.options.path; return exists(dbPath).then(exist => { @@ -21,7 +22,7 @@ function deleteDatabase(ctx) { }); } -function deletePublicDir(ctx) { +function deletePublicDir(ctx: Hexo): Promise { const publicDir = ctx.public_dir; return exists(publicDir).then(exist => { diff --git a/lib/plugins/console/config.ts b/lib/plugins/console/config.ts index 841c241c23..777bc4e1d0 100644 --- a/lib/plugins/console/config.ts +++ b/lib/plugins/console/config.ts @@ -2,8 +2,9 @@ import yaml from 'js-yaml'; import { exists, writeFile } from 'hexo-fs'; import { extname } from 'path'; import Promise from 'bluebird'; +import type Hexo from '../../hexo'; -function configConsole(args) { +function configConsole(this: Hexo, args): Promise { const key = args._[0]; let value = args._[1]; @@ -35,7 +36,7 @@ function configConsole(args) { }); } -function getProperty(obj, key) { +function getProperty(obj: object, key: string): any { const split = key.split('.'); let result = obj[split[0]]; @@ -46,7 +47,7 @@ function getProperty(obj, key) { return result; } -function setProperty(obj, key, value) { +function setProperty(obj: object, key: string, value: any): void { const split = key.split('.'); let cursor = obj; const lastKey = split.pop(); @@ -60,7 +61,7 @@ function setProperty(obj, key, value) { cursor[lastKey] = value; } -function castValue(value) { +function castValue(value: string): any { switch (value) { case 'true': return true; diff --git a/lib/plugins/console/deploy.ts b/lib/plugins/console/deploy.ts index 6da32c2e76..1da54819d4 100644 --- a/lib/plugins/console/deploy.ts +++ b/lib/plugins/console/deploy.ts @@ -1,7 +1,8 @@ import { exists } from 'hexo-fs'; import { underline, magenta } from 'picocolors'; +import type Hexo from '../../hexo'; -function deployConsole(args) { +function deployConsole(this: Hexo, args) { let config = this.config.deploy; const deployers = this.extend.deployer.list(); diff --git a/lib/plugins/console/generate.ts b/lib/plugins/console/generate.ts index ccae2b3d94..2b17697b49 100644 --- a/lib/plugins/console/generate.ts +++ b/lib/plugins/console/generate.ts @@ -6,21 +6,22 @@ import { cyan, magenta } from 'picocolors'; import tildify from 'tildify'; import { PassThrough } from 'stream'; import { createSha1Hash } from 'hexo-util'; +import type Hexo from '../../hexo'; class Generater { - public context: any; + public context: Hexo; public force: any; public bail: any; public concurrency: any; public watch: any; public deploy: any; - public generatingFiles: any; - public start: any; + public generatingFiles: Set; + public start: [number, number]; public args: any; public route: any; public log: any; - constructor(ctx, args) { + constructor(ctx: Hexo, args) { this.context = ctx; this.force = args.f || args.force; this.bail = args.b || args.bail; @@ -31,7 +32,7 @@ class Generater { this.start = process.hrtime(); this.args = args; } - generateFile(path) { + generateFile(path: string) { const publicDir = this.context.public_dir; const { generatingFiles } = this; const { route } = this.context; @@ -58,7 +59,7 @@ class Generater { generatingFiles.delete(path); }); } - writeFile(path, force?) { + writeFile(path: string, force?: boolean): Promise { const { route, log } = this.context; const publicDir = this.context.public_dir; const Cache = this.context.model('Cache'); @@ -99,7 +100,7 @@ class Generater { }); }); } - deleteFile(path) { + deleteFile(path: string): Promise { const { log } = this.context; const publicDir = this.context.public_dir; const dest = join(publicDir, path); @@ -126,7 +127,7 @@ class Generater { return dataStream.pipe(new PassThrough()); } - firstGenerate() { + firstGenerate(): Promise { const { concurrency } = this; const { route, log } = this.context; const publicDir = this.context.public_dir; @@ -171,7 +172,7 @@ class Generater { log.info('%d files generated in %s', count, cyan(interval)); }); } - execWatch() { + execWatch(): Promise { const { route, log } = this.context; return this.context.watch().then(() => this.firstGenerate()).then(() => { log.info('Hexo is watching for file changes. Press Ctrl+C to exit.'); diff --git a/lib/plugins/console/list/category.ts b/lib/plugins/console/list/category.ts index 0044ec3a0e..a1c6527c80 100644 --- a/lib/plugins/console/list/category.ts +++ b/lib/plugins/console/list/category.ts @@ -1,8 +1,9 @@ import { underline } from 'picocolors'; import table from 'text-table'; import { stringLength } from './common'; +import type Hexo from '../../../hexo'; -function listCategory() { +function listCategory(this: Hexo): void { const categories = this.model('Category'); const data = categories.sort({name: 1}).map(cate => [cate.name, String(cate.length)]); diff --git a/lib/plugins/console/list/common.ts b/lib/plugins/console/list/common.ts index 5adcb8022c..cc18685f5c 100644 --- a/lib/plugins/console/list/common.ts +++ b/lib/plugins/console/list/common.ts @@ -1,6 +1,6 @@ import strip from 'strip-ansi'; -export function stringLength(str) { +export function stringLength(str: string): number { str = strip(str); const len = str.length; diff --git a/lib/plugins/console/list/index.ts b/lib/plugins/console/list/index.ts index 7c3f084138..cd091ca272 100644 --- a/lib/plugins/console/list/index.ts +++ b/lib/plugins/console/list/index.ts @@ -4,6 +4,7 @@ import post from './post'; import route from './route'; import tag from './tag'; import category from './category'; +import type Hexo from '../../../hexo'; const store = { page, post, route, tag, category @@ -11,7 +12,7 @@ const store = { const alias = abbrev(Object.keys(store)); -function listConsole(args) { +function listConsole(this: Hexo, args) { const type = args._.shift(); // Display help message if user didn't input any arguments diff --git a/lib/plugins/console/list/page.ts b/lib/plugins/console/list/page.ts index d132231450..8b9de1bc09 100644 --- a/lib/plugins/console/list/page.ts +++ b/lib/plugins/console/list/page.ts @@ -1,8 +1,9 @@ import { magenta, underline, gray } from 'picocolors'; import table from 'text-table'; import { stringLength } from './common'; +import type Hexo from '../../../hexo'; -function listPage() { +function listPage(this: Hexo): void { const Page = this.model('Page'); const data = Page.sort({date: 1}).map(page => { diff --git a/lib/plugins/console/list/post.ts b/lib/plugins/console/list/post.ts index e4dca1a578..280b339df8 100644 --- a/lib/plugins/console/list/post.ts +++ b/lib/plugins/console/list/post.ts @@ -1,12 +1,13 @@ import { gray, magenta, underline } from 'picocolors'; import table from 'text-table'; import { stringLength } from './common'; +import type Hexo from '../../../hexo'; function mapName(item) { return item.name; } -function listPost() { +function listPost(this: Hexo): void { const Post = this.model('Post'); const data = Post.sort({published: -1, date: 1}).map(post => { diff --git a/lib/plugins/console/list/route.ts b/lib/plugins/console/list/route.ts index a29e4e4c54..2c15e217cc 100644 --- a/lib/plugins/console/list/route.ts +++ b/lib/plugins/console/list/route.ts @@ -1,6 +1,7 @@ import archy from 'archy'; +import type Hexo from '../../../hexo'; -function listRoute() { +function listRoute(this: Hexo): void { const routes = this.route.list().sort(); const tree = buildTree(routes); const nodes = buildNodes(tree); diff --git a/lib/plugins/console/list/tag.ts b/lib/plugins/console/list/tag.ts index 09c0a148df..4ce37595d1 100644 --- a/lib/plugins/console/list/tag.ts +++ b/lib/plugins/console/list/tag.ts @@ -1,8 +1,9 @@ import { magenta, underline } from 'picocolors'; import table from 'text-table'; import { stringLength } from './common'; +import type Hexo from '../../../hexo'; -function listTag() { +function listTag(this: Hexo): void { const Tag = this.model('Tag'); const data = Tag.sort({name: 1}).map(tag => [tag.name, String(tag.length), magenta(tag.path)]); diff --git a/lib/plugins/console/migrate.ts b/lib/plugins/console/migrate.ts index df341f6ed4..afe5dfb537 100644 --- a/lib/plugins/console/migrate.ts +++ b/lib/plugins/console/migrate.ts @@ -1,6 +1,7 @@ import { underline, magenta } from 'picocolors'; +import type Hexo from '../../hexo'; -function migrateConsole(args) { +function migrateConsole(this: Hexo, args) { // 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 becbe1c625..64e3d83bd1 100644 --- a/lib/plugins/console/new.ts +++ b/lib/plugins/console/new.ts @@ -1,6 +1,7 @@ import tildify from 'tildify'; import { magenta } from 'picocolors'; import { basename } from 'path'; +import Hexo from '../../hexo'; const reservedKeys = { _: true, @@ -19,7 +20,7 @@ const reservedKeys = { silent: true }; -function newConsole(args) { +function newConsole(this: Hexo, args) { const path = args.p || args.path; let title; if (args._.length) { diff --git a/lib/plugins/console/publish.ts b/lib/plugins/console/publish.ts index f73d87ec55..6f97f9d175 100644 --- a/lib/plugins/console/publish.ts +++ b/lib/plugins/console/publish.ts @@ -1,7 +1,8 @@ import tildify from 'tildify'; import { magenta } from 'picocolors'; +import type Hexo from '../../hexo'; -function publishConsole(args) { +function publishConsole(this: Hexo, args) { // 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 01cb57c581..c40230f728 100644 --- a/lib/plugins/console/render.ts +++ b/lib/plugins/console/render.ts @@ -3,8 +3,9 @@ import tildify from 'tildify'; import prettyHrtime from 'pretty-hrtime'; import { writeFile } from 'hexo-fs'; import { cyan, magenta } from 'picocolors'; +import type Hexo from '../../hexo'; -function renderConsole(args) { +function renderConsole(this: Hexo, args) { // Display help message if user didn't input any arguments if (!args._.length) { return this.call('help', {_: 'render'}); diff --git a/lib/plugins/filter/after_post_render/excerpt.ts b/lib/plugins/filter/after_post_render/excerpt.ts index ef1746a352..5694ce5dec 100644 --- a/lib/plugins/filter/after_post_render/excerpt.ts +++ b/lib/plugins/filter/after_post_render/excerpt.ts @@ -1,6 +1,6 @@ const rExcerpt = //i; -function excerptFilter(data) { +function excerptFilter(data): void { const { content } = data; if (typeof data.excerpt !== 'undefined') { diff --git a/lib/plugins/filter/after_post_render/external_link.ts b/lib/plugins/filter/after_post_render/external_link.ts index 0b116de8b4..dab35b3a9d 100644 --- a/lib/plugins/filter/after_post_render/external_link.ts +++ b/lib/plugins/filter/after_post_render/external_link.ts @@ -1,11 +1,12 @@ import { isExternalLink } from 'hexo-util'; +import type Hexo from '../../../hexo'; let EXTERNAL_LINK_POST_ENABLED = true; const rATag = /]+?\s+?)href=["']((?:https?:|\/\/)[^<>"']+)["'][^<>]*>/gi; const rTargetAttr = /target=/i; const rRelAttr = /rel=/i; const rRelStrAttr = /rel=["']([^<>"']*)["']/i; -function externalLinkFilter(data) { +function externalLinkFilter(this: Hexo, data): void { if (!EXTERNAL_LINK_POST_ENABLED) return; const { external_link, url } = this.config; @@ -16,7 +17,7 @@ function externalLinkFilter(data) { } data.content = data.content.replace(rATag, (str, href) => { - if (!isExternalLink(href, url, external_link.exclude) || rTargetAttr.test(str)) return str; + if (!isExternalLink(href, url, external_link.exclude as any) || rTargetAttr.test(str)) return str; if (rRelAttr.test(str)) { str = str.replace(rRelStrAttr, (relStr, rel) => { diff --git a/lib/plugins/filter/after_post_render/index.ts b/lib/plugins/filter/after_post_render/index.ts index 87bb8b433c..014eb0b6d0 100644 --- a/lib/plugins/filter/after_post_render/index.ts +++ b/lib/plugins/filter/after_post_render/index.ts @@ -1,4 +1,6 @@ -export = ctx => { +import type Hexo from '../../../hexo'; + +export = (ctx: Hexo) => { const { filter } = ctx.extend; filter.register('after_post_render', require('./external_link')); diff --git a/lib/plugins/filter/after_render/external_link.ts b/lib/plugins/filter/after_render/external_link.ts index a5d7218133..7a0168d842 100644 --- a/lib/plugins/filter/after_render/external_link.ts +++ b/lib/plugins/filter/after_render/external_link.ts @@ -1,4 +1,5 @@ import { isExternalLink } from 'hexo-util'; +import Hexo from '../../../hexo'; let EXTERNAL_LINK_SITE_ENABLED = true; const rATag = /]+?\s+?)href=["']((?:https?:|\/\/)[^<>"']+)["'][^<>]*>/gi; @@ -6,7 +7,7 @@ const rTargetAttr = /target=/i; const rRelAttr = /rel=/i; const rRelStrAttr = /rel=["']([^<>"']*)["']/i; -function externalLinkFilter(data) { +function externalLinkFilter(this: Hexo, data: string): string { if (!EXTERNAL_LINK_SITE_ENABLED) return; const { external_link, url } = this.config; @@ -17,7 +18,7 @@ function externalLinkFilter(data) { } return data.replace(rATag, (str, href) => { - if (!isExternalLink(href, url, external_link.exclude) || rTargetAttr.test(str)) return str; + if (!isExternalLink(href, url, external_link.exclude as any) || rTargetAttr.test(str)) return str; if (rRelAttr.test(str)) { str = str.replace(rRelStrAttr, (relStr, rel) => { diff --git a/lib/plugins/filter/after_render/index.ts b/lib/plugins/filter/after_render/index.ts index 509e95a0f8..a1eb862d5a 100644 --- a/lib/plugins/filter/after_render/index.ts +++ b/lib/plugins/filter/after_render/index.ts @@ -1,4 +1,6 @@ -export = ctx => { +import type Hexo from '../../../hexo'; + +export = (ctx: Hexo) => { const { filter } = ctx.extend; filter.register('after_render:html', require('./external_link')); diff --git a/lib/plugins/filter/after_render/meta_generator.ts b/lib/plugins/filter/after_render/meta_generator.ts index 4c04daee3a..7848f435ee 100644 --- a/lib/plugins/filter/after_render/meta_generator.ts +++ b/lib/plugins/filter/after_render/meta_generator.ts @@ -1,7 +1,9 @@ +import type Hexo from '../../../hexo'; + let NEED_INJECT = true; let META_GENERATOR_TAG; -function hexoMetaGeneratorInject(data) { +function hexoMetaGeneratorInject(this: Hexo, data: string): string { if (!NEED_INJECT) return; if (!this.config.meta_generator diff --git a/lib/plugins/filter/before_exit/index.ts b/lib/plugins/filter/before_exit/index.ts index ba3312749e..1443eed5cb 100644 --- a/lib/plugins/filter/before_exit/index.ts +++ b/lib/plugins/filter/before_exit/index.ts @@ -1,4 +1,6 @@ -export = ctx => { +import type Hexo from '../../../hexo'; + +export = (ctx: Hexo) => { const { filter } = ctx.extend; filter.register('before_exit', require('./save_database')); diff --git a/lib/plugins/filter/before_exit/save_database.ts b/lib/plugins/filter/before_exit/save_database.ts index 9aadce2ee8..9a853eb93e 100644 --- a/lib/plugins/filter/before_exit/save_database.ts +++ b/lib/plugins/filter/before_exit/save_database.ts @@ -1,4 +1,6 @@ -function saveDatabaseFilter() { +import type Hexo from '../../../hexo'; + +function saveDatabaseFilter(this: Hexo) { if (!this.env.init || !this._dbLoaded) return; return this.database.save().then(() => { diff --git a/lib/plugins/filter/before_generate/index.ts b/lib/plugins/filter/before_generate/index.ts index 288bb1651a..9c9565b9f4 100644 --- a/lib/plugins/filter/before_generate/index.ts +++ b/lib/plugins/filter/before_generate/index.ts @@ -1,4 +1,6 @@ -export = ctx => { +import type Hexo from '../../../hexo'; + +export = (ctx: Hexo) => { const { filter } = ctx.extend; filter.register('before_generate', require('./render_post')); diff --git a/lib/plugins/filter/before_generate/render_post.ts b/lib/plugins/filter/before_generate/render_post.ts index 539b5dadda..0a6cbe78d8 100644 --- a/lib/plugins/filter/before_generate/render_post.ts +++ b/lib/plugins/filter/before_generate/render_post.ts @@ -1,6 +1,7 @@ import Promise from 'bluebird'; +import type Hexo from '../../../hexo'; -function renderPostFilter() { +function renderPostFilter(this: Hexo): Promise<[any[], any[]]> { const renderPosts = model => { const posts = model.toArray().filter(post => post.content == null); diff --git a/lib/plugins/filter/before_post_render/backtick_code_block.ts b/lib/plugins/filter/before_post_render/backtick_code_block.ts index b9df3e60f2..7952169edd 100644 --- a/lib/plugins/filter/before_post_render/backtick_code_block.ts +++ b/lib/plugins/filter/before_post_render/backtick_code_block.ts @@ -1,3 +1,5 @@ +import type Hexo from '../../../hexo'; + const rBacktick = /^((?:[^\S\r\n]*>){0,3}[^\S\r\n]*)(`{3,}|~{3,})[^\S\r\n]*((?:.*?[^`\s])?)[^\S\r\n]*\n((?:[\s\S]*?\n)?)(?:(?:[^\S\r\n]*>){0,3}[^\S\r\n]*)\2[^\S\r\n]?(\n+|$)/gm; const rAllOptions = /([^\s]+)\s+(.+?)\s+(https?:\/\/\S+|\/\S+)\s*(.+)?/; const rLangCaption = /([^\s]+)\s*(.+)?/; @@ -11,8 +13,8 @@ interface Options { firstLineNumber?: string | number } -export = ctx => { - return function backtickCodeBlock(data) { +export = (ctx: Hexo) => { + return function backtickCodeBlock(data): void { const dataContent = data.content; if ((!dataContent.includes('```') && !dataContent.includes('~~~')) || !ctx.extend.highlight.query(ctx.config.syntax_highlighter)) return; diff --git a/lib/plugins/filter/before_post_render/index.ts b/lib/plugins/filter/before_post_render/index.ts index 07bde83da3..501b483df7 100644 --- a/lib/plugins/filter/before_post_render/index.ts +++ b/lib/plugins/filter/before_post_render/index.ts @@ -1,4 +1,6 @@ -export = ctx => { +import type Hexo from '../../../hexo'; + +export = (ctx: Hexo) => { const { filter } = ctx.extend; filter.register('before_post_render', require('./backtick_code_block')(ctx)); diff --git a/lib/plugins/filter/before_post_render/titlecase.ts b/lib/plugins/filter/before_post_render/titlecase.ts index 24e596ace8..bd149d3823 100644 --- a/lib/plugins/filter/before_post_render/titlecase.ts +++ b/lib/plugins/filter/before_post_render/titlecase.ts @@ -1,6 +1,6 @@ let titlecase; -function titlecaseFilter(data) { +function titlecaseFilter(data): void { if (!(typeof data.titlecase !== 'undefined' ? data.titlecase : this.config.titlecase) || !data.title) return; if (!titlecase) titlecase = require('titlecase'); diff --git a/lib/plugins/filter/new_post_path.ts b/lib/plugins/filter/new_post_path.ts index c06b946230..1eaa58c9f2 100644 --- a/lib/plugins/filter/new_post_path.ts +++ b/lib/plugins/filter/new_post_path.ts @@ -3,6 +3,7 @@ import moment from 'moment'; import Promise from 'bluebird'; import { createSha1Hash, Permalink } from 'hexo-util'; import { ensurePath } from 'hexo-fs'; +import type Hexo from '../../hexo'; let permalink; const reservedKeys = { @@ -22,7 +23,7 @@ interface Data { date?: Date; } -function newPostPathFilter(data: Data = {}, replace) { +function newPostPathFilter(this: Hexo, data: Data = {}, replace): Promise { const sourceDir = this.source_dir; const draftDir = join(sourceDir, '_drafts'); const postDir = join(sourceDir, '_posts'); diff --git a/lib/plugins/filter/post_permalink.ts b/lib/plugins/filter/post_permalink.ts index c715e67b5d..f066421330 100644 --- a/lib/plugins/filter/post_permalink.ts +++ b/lib/plugins/filter/post_permalink.ts @@ -1,8 +1,9 @@ import { createSha1Hash, Permalink, slugize } from 'hexo-util'; import { basename } from 'path'; +import type Hexo from '../../hexo'; let permalink; -function postPermalinkFilter(data) { +function postPermalinkFilter(this: Hexo, data) { const { config } = this; const { id, _id, slug, title, date, __permalink } = data; diff --git a/lib/plugins/filter/template_locals/i18n.ts b/lib/plugins/filter/template_locals/i18n.ts index 73367d8df0..a709fe8934 100644 --- a/lib/plugins/filter/template_locals/i18n.ts +++ b/lib/plugins/filter/template_locals/i18n.ts @@ -1,6 +1,7 @@ import { Pattern } from 'hexo-util'; +import type Hexo from '../../../hexo'; -function i18nLocalsFilter(locals) { +function i18nLocalsFilter(this: Hexo, locals): void { const { i18n } = this.theme; const { config } = this; const i18nDir = config.i18n_dir; diff --git a/lib/plugins/filter/template_locals/index.ts b/lib/plugins/filter/template_locals/index.ts index 663cb8ab3f..27dbf0caa4 100644 --- a/lib/plugins/filter/template_locals/index.ts +++ b/lib/plugins/filter/template_locals/index.ts @@ -1,4 +1,6 @@ -export = ctx => { +import type Hexo from '../../../hexo'; + +export = (ctx: Hexo) => { const { filter } = ctx.extend; filter.register('template_locals', require('./i18n')); diff --git a/lib/plugins/generator/asset.ts b/lib/plugins/generator/asset.ts index 722807c52e..074f497620 100644 --- a/lib/plugins/generator/asset.ts +++ b/lib/plugins/generator/asset.ts @@ -4,13 +4,14 @@ import Promise from 'bluebird'; import { extname } from 'path'; import { magenta } from 'picocolors'; import type warehouse from 'warehouse'; +import type Hexo from '../../hexo'; interface Data { modified: boolean; data?: () => any; } -const process = (name, ctx) => { +const process = (name: string, ctx: Hexo) => { // @ts-expect-error return Promise.filter(ctx.model(name).toArray(), (asset: warehouse['Schema']) => exists(asset.source).tap(exist => { // @ts-expect-error @@ -46,7 +47,7 @@ const process = (name, ctx) => { }); }; -function assetGenerator() { +function assetGenerator(this: Hexo): Promise { return Promise.all([ process('Asset', this), process('PostAsset', this) diff --git a/lib/plugins/helper/css.ts b/lib/plugins/helper/css.ts index 74ca0ba357..9dac2e3588 100644 --- a/lib/plugins/helper/css.ts +++ b/lib/plugins/helper/css.ts @@ -2,7 +2,7 @@ import { htmlTag, url_for } from 'hexo-util'; import moize from 'moize'; let relative_link = true; -function cssHelper(...args) { +function cssHelper(...args: any[]) { let result = '\n'; relative_link = this.config.relative_link; diff --git a/lib/plugins/helper/date.ts b/lib/plugins/helper/date.ts index b347770dc8..8d45b27147 100644 --- a/lib/plugins/helper/date.ts +++ b/lib/plugins/helper/date.ts @@ -1,13 +1,14 @@ import moment from 'moment-timezone'; const { isMoment } = moment; import moize from 'moize'; +import type Hexo from '../../hexo'; -const isDate = value => +const isDate = (value: moment.MomentInput | moment.Moment): boolean => typeof value === 'object' && value instanceof Date && !isNaN(value.getTime()); -function getMoment(date, lang, timezone) { +function getMoment(date: moment.MomentInput | moment.Moment, lang: string, timezone: string): moment.Moment { if (date == null) date = moment(); - if (!isMoment(date)) date = moment(isDate(date) ? date : new Date(date)); + if (!isMoment(date)) date = moment(isDate(date) ? date : new Date(date)); lang = _toMomentLocale(lang); if (lang) date = date.locale(lang); @@ -16,7 +17,7 @@ function getMoment(date, lang, timezone) { return date; } -function toISOString(date) { +function toISOString(date: string | number | Date | moment.Moment) { if (date == null) { return new Date().toISOString(); } @@ -25,22 +26,22 @@ function toISOString(date) { return date.toISOString(); } - return new Date(date).toISOString(); + return new Date(date as (string | number)).toISOString(); } -function dateHelper(date, format) { +function dateHelper(date: moment.Moment | moment.MomentInput, format: string) { const { config } = this; const moment = getMoment(date, getLanguage(this), config.timezone); return moment.format(format || config.date_format); } -function timeHelper(date, format) { +function timeHelper(date: moment.Moment | moment.MomentInput, format: string) { const { config } = this; const moment = getMoment(date, getLanguage(this), config.timezone); return moment.format(format || config.time_format); } -function fullDateHelper(date, format) { +function fullDateHelper(date: moment.Moment | moment.MomentInput, format: string) { if (format) { const moment = getMoment(date, getLanguage(this), this.config.timezone); return moment.format(format); @@ -49,13 +50,13 @@ function fullDateHelper(date, format) { return `${this.date(date)} ${this.time(date)}`; } -function relativeDateHelper(date) { +function relativeDateHelper(date: moment.Moment | moment.MomentInput) { const { config } = this; const moment = getMoment(date, getLanguage(this), config.timezone); return moment.fromNow(); } -function timeTagHelper(date, format) { +function timeTagHelper(date: string | number | Date | moment.Moment, format: string) { const { config } = this; return ``; } @@ -72,7 +73,7 @@ function getLanguage(ctx) { * * Moment defined locales: https://github.com/moment/moment/tree/master/locale */ -function _toMomentLocale(lang) { +function _toMomentLocale(lang: string) { if (lang === undefined) { return undefined; } diff --git a/lib/plugins/helper/debug.ts b/lib/plugins/helper/debug.ts index ba4a96983f..a097223bb9 100644 --- a/lib/plugins/helper/debug.ts +++ b/lib/plugins/helper/debug.ts @@ -1,12 +1,12 @@ import { inspect } from 'util'; // this format object as string, resolves circular reference -function inspectObject(object, options) { +function inspectObject(object: any, options: boolean) { return inspect(object, options); } // wrapper to log to console -function log(...args) { +function log(...args: any[]) { return Reflect.apply(console.log, null, args); } diff --git a/lib/plugins/helper/favicon_tag.ts b/lib/plugins/helper/favicon_tag.ts index 579c04379a..3c00b5dbd5 100644 --- a/lib/plugins/helper/favicon_tag.ts +++ b/lib/plugins/helper/favicon_tag.ts @@ -1,6 +1,6 @@ import { url_for } from 'hexo-util'; -function faviconTagHelper(path) { +function faviconTagHelper(path: string) { return ``; } diff --git a/lib/plugins/helper/feed_tag.ts b/lib/plugins/helper/feed_tag.ts index 8fccfc7738..bb8bca13ab 100644 --- a/lib/plugins/helper/feed_tag.ts +++ b/lib/plugins/helper/feed_tag.ts @@ -11,7 +11,7 @@ interface Options { type?: string; } -function makeFeedTag(path, options: Options = {}, configFeed?, configTitle?) { +function makeFeedTag(path: string, options: Options = {}, configFeed?: any, configTitle?: string) { const title = options.title || configTitle; if (path) { @@ -46,7 +46,7 @@ function makeFeedTag(path, options: Options = {}, configFeed?, configTitle?) { return ''; } -function feedTagHelper(path, options = {}) { +function feedTagHelper(path: string, options = {}) { const { config } = this; return moize.deep(makeFeedTag.bind(this))(path, options, config.feed, config.title); } diff --git a/lib/plugins/helper/format.ts b/lib/plugins/helper/format.ts index c9372b507e..745e9901ff 100644 --- a/lib/plugins/helper/format.ts +++ b/lib/plugins/helper/format.ts @@ -3,7 +3,7 @@ import titlecase from 'titlecase'; export {stripHTML as strip_html}; export {stripHTML}; -export function trim(str) { +export function trim(str: string) { return str.trim(); } diff --git a/lib/plugins/helper/fragment_cache.ts b/lib/plugins/helper/fragment_cache.ts index 1c38229e0c..91926b919f 100644 --- a/lib/plugins/helper/fragment_cache.ts +++ b/lib/plugins/helper/fragment_cache.ts @@ -1,7 +1,7 @@ - import { Cache } from 'hexo-util'; +import type Hexo from '../../hexo'; -export = ctx => { +export = (ctx: Hexo) => { const cache = new Cache(); // reset cache for watch mode diff --git a/lib/plugins/helper/full_url_for.ts b/lib/plugins/helper/full_url_for.ts index 4e77338082..9484f0e537 100644 --- a/lib/plugins/helper/full_url_for.ts +++ b/lib/plugins/helper/full_url_for.ts @@ -1,6 +1,6 @@ import { full_url_for } from 'hexo-util'; -export = function(path) { +export = function(path: string) { return full_url_for.call(this, path); } diff --git a/lib/plugins/helper/js.ts b/lib/plugins/helper/js.ts index 24ca0fca3d..8ca44e5c52 100644 --- a/lib/plugins/helper/js.ts +++ b/lib/plugins/helper/js.ts @@ -2,7 +2,7 @@ import { htmlTag, url_for } from 'hexo-util'; import moize from 'moize'; let relative_link = true; -function jsHelper(...args) { +function jsHelper(...args: any[]) { let result = '\n'; relative_link = this.config.relative_link; diff --git a/lib/plugins/helper/list_categories.ts b/lib/plugins/helper/list_categories.ts index ff248d6bf3..b2c1fd4e58 100644 --- a/lib/plugins/helper/list_categories.ts +++ b/lib/plugins/helper/list_categories.ts @@ -33,7 +33,7 @@ function listCategoriesHelper(categories, options) { const hierarchicalList = (level: number, parent?: any) => { let result = ''; - prepareQuery(parent).forEach((cat, i) => { + prepareQuery(parent).forEach(cat => { let child; if (!depth || level + 1 < depth) { child = hierarchicalList(level + 1, cat._id); diff --git a/lib/plugins/helper/mail_to.ts b/lib/plugins/helper/mail_to.ts index 90f9ef88c9..be102ef516 100644 --- a/lib/plugins/helper/mail_to.ts +++ b/lib/plugins/helper/mail_to.ts @@ -14,7 +14,7 @@ interface Attrs { [key: string]: string | boolean | null | undefined; } -function mailToHelper(path, text, options: Options = {}) { +function mailToHelper(path: string, text: string, options: Options = {}) { if (Array.isArray(path)) path = path.join(','); if (!text) text = path; diff --git a/lib/plugins/helper/markdown.ts b/lib/plugins/helper/markdown.ts index 956425f072..9465bbb671 100644 --- a/lib/plugins/helper/markdown.ts +++ b/lib/plugins/helper/markdown.ts @@ -1,4 +1,4 @@ -function markdownHelper(text, options) { +function markdownHelper(text: string, options) { return this.render(text, 'markdown', options); } diff --git a/lib/plugins/helper/open_graph.ts b/lib/plugins/helper/open_graph.ts index 9209eeda63..27d142f8bc 100644 --- a/lib/plugins/helper/open_graph.ts +++ b/lib/plugins/helper/open_graph.ts @@ -34,7 +34,7 @@ const localeToTerritory = moize.shallow(str => { } }); -const meta = (name, content, escape?: boolean) => { +const meta = (name: string, content: string | URL, escape?: boolean) => { if (escape !== false && typeof content === 'string') { content = escapeHTML(content); } @@ -43,7 +43,7 @@ const meta = (name, content, escape?: boolean) => { return `\n`; }; -const og = (name, content?: string, escape?: boolean) => { +const og = (name: string, content?: string, escape?: boolean) => { if (escape !== false && typeof content === 'string') { content = escapeHTML(content); } diff --git a/lib/plugins/helper/paginator.ts b/lib/plugins/helper/paginator.ts index 8d37c80739..429aff8b4d 100644 --- a/lib/plugins/helper/paginator.ts +++ b/lib/plugins/helper/paginator.ts @@ -1,12 +1,35 @@ import { htmlTag, url_for } from 'hexo-util'; +import type Hexo from '../../hexo'; -const createLink = (options, ctx) => { +interface Options { + base?: string; + current?: number; + format?: string; + total?: number; + end_size?: number; + mid_size?: number; + space?: string; + next_text?: string; + prev_text?: string; + prev_next?: boolean; + escape?: boolean; + page_class?: string; + current_class?: string; + space_class?: string; + prev_class?: string; + next_class?: string; + force_prev_next?: boolean; + show_all?: boolean; + transform?: (i: number) => any; +} + +const createLink = (options: Options, ctx: Hexo) => { const { base, format } = options; - return i => url_for.call(ctx, i === 1 ? base : base + format.replace('%d', i)); + return (i: number) => url_for.call(ctx, i === 1 ? base : base + format.replace('%d', String(i))); }; -const createPageTag = (options, ctx) => { +const createPageTag = (options: Options, ctx: Hexo) => { const link = createLink(options, ctx); const { current, @@ -16,7 +39,7 @@ const createPageTag = (options, ctx) => { current_class: currentClass } = options; - return i => { + return (i: number) => { if (i === current) { return htmlTag('span', { class: pageClass + ' ' + currentClass }, transform ? transform(i) : i, escape); } @@ -24,7 +47,7 @@ const createPageTag = (options, ctx) => { }; }; -const showAll = (tags, options, ctx) => { +const showAll = (tags: string[], options: Options, ctx: Hexo) => { const { total } = options; const pageLink = createPageTag(options, ctx); @@ -34,7 +57,7 @@ const showAll = (tags, options, ctx) => { } }; -const paginationPartShow = (tags, options, ctx) => { +const paginationPartShow = (tags, options, ctx: Hexo) => { const { current, total, @@ -86,27 +109,6 @@ const paginationPartShow = (tags, options, ctx) => { } }; -interface Options { - base?: string; - current?: number; - format?: string; - total?: number; - end_size?: number; - mid_size?: number; - space?: string; - next_text?: string; - prev_text?: string; - prev_next?: boolean; - escape?: boolean; - page_class?: string; - current_class?: string; - space_class?: string; - prev_class?: string; - next_class?: string; - force_prev_next?: boolean; - show_all?: boolean; -} - function paginatorHelper(options: Options = {}) { options = Object.assign({ base: this.page.base || '', diff --git a/lib/plugins/helper/partial.ts b/lib/plugins/helper/partial.ts index d548a58ba9..fac560117d 100644 --- a/lib/plugins/helper/partial.ts +++ b/lib/plugins/helper/partial.ts @@ -1,11 +1,12 @@ import { dirname, join } from 'path'; +import type Hexo from '../../hexo'; interface Options { cache?: boolean | string; only?: boolean; } -export = ctx => function partial(name, locals, options: Options = {}) { +export = (ctx: Hexo) => function partial(name: string, locals: any, options: Options = {}) { if (typeof name !== 'string') throw new TypeError('name must be a string!'); const { cache } = options; diff --git a/lib/plugins/helper/relative_url.ts b/lib/plugins/helper/relative_url.ts index 631a9946fd..62ebaa16e2 100644 --- a/lib/plugins/helper/relative_url.ts +++ b/lib/plugins/helper/relative_url.ts @@ -1,5 +1,5 @@ import { relative_url } from 'hexo-util'; -export = function(from, to) { +export = function(from: string, to: string) { return relative_url(from, to); } diff --git a/lib/plugins/helper/render.ts b/lib/plugins/helper/render.ts index 9f8473efb3..4d2d7414b3 100644 --- a/lib/plugins/helper/render.ts +++ b/lib/plugins/helper/render.ts @@ -1,4 +1,6 @@ -export = ctx => function render(text, engine, options) { +import type Hexo from '../../hexo'; + +export = (ctx: Hexo) => function render(text: string, engine: string, options:object = {}) { return ctx.render.renderSync({ text, engine diff --git a/lib/plugins/helper/toc.ts b/lib/plugins/helper/toc.ts index 4abec4d30b..02a4b1ad7d 100644 --- a/lib/plugins/helper/toc.ts +++ b/lib/plugins/helper/toc.ts @@ -13,7 +13,7 @@ interface Options { list_number?: boolean; } -function tocHelper(str, options: Options = {}) { +function tocHelper(str: string, options: Options = {}) { options = Object.assign({ min_depth: 1, max_depth: 6, diff --git a/lib/plugins/helper/url_for.ts b/lib/plugins/helper/url_for.ts index 49e7a5f124..e7c58dd05d 100644 --- a/lib/plugins/helper/url_for.ts +++ b/lib/plugins/helper/url_for.ts @@ -1,5 +1,9 @@ import { url_for } from 'hexo-util'; -export = function(path, options) { +interface Options { + relative?: boolean +} + +export = function(path: string, options: Options = {}) { return url_for.call(this, path, options); } diff --git a/lib/plugins/processor/asset.ts b/lib/plugins/processor/asset.ts index 9693bbaeb5..c56ff62052 100644 --- a/lib/plugins/processor/asset.ts +++ b/lib/plugins/processor/asset.ts @@ -4,8 +4,11 @@ import { parse as yfm } from 'hexo-front-matter'; import { extname, relative } from 'path'; import { Pattern } from 'hexo-util'; import { magenta } from 'picocolors'; +import type { _File } from '../../box'; +import type Hexo from '../../hexo'; +import type { Stats } from 'fs'; -export = ctx => { +export = (ctx: Hexo) => { return { pattern: new Pattern(path => { if (isExcludedFile(path, ctx.config)) return; @@ -15,7 +18,7 @@ export = ctx => { }; }), - process: function assetProcessor(file) { + process: function assetProcessor(file: _File) { if (file.params.renderable) { return processPage(ctx, file); } @@ -25,7 +28,7 @@ export = ctx => { }; }; -function processPage(ctx, file) { +function processPage(ctx: Hexo, file: _File) { const Page = ctx.model('Page'); const { path } = file; const doc = Page.findOne({source: path}); @@ -48,7 +51,7 @@ function processPage(ctx, file) { return Promise.all([ file.stat(), file.read() - ]).spread((stats, content) => { + ]).spread((stats: Stats, content: string) => { const data = yfm(content); const output = ctx.render.getOutput(path); @@ -105,7 +108,7 @@ function processPage(ctx, file) { }); } -function processAsset(ctx, file) { +function processAsset(ctx: Hexo, file: _File) { const id = relative(ctx.base_dir, file.source).replace(/\\/g, '/'); const Asset = ctx.model('Asset'); const doc = Asset.findById(id); diff --git a/lib/plugins/processor/common.ts b/lib/plugins/processor/common.ts index c981536598..fa5202b633 100644 --- a/lib/plugins/processor/common.ts +++ b/lib/plugins/processor/common.ts @@ -4,21 +4,21 @@ import micromatch from 'micromatch'; const DURATION_MINUTE = 1000 * 60; -function isMatch(path, patterns) { +function isMatch(path: string, patterns: string| string[]) { if (!patterns) return false; return micromatch.isMatch(path, patterns); } -function isTmpFile(path) { +function isTmpFile(path: string) { return path.endsWith('%') || path.endsWith('~'); } -function isHiddenFile(path) { +function isHiddenFile(path: string) { return /(^|\/)[_.]/.test(path); } -function isExcludedFile(path, config) { +function isExcludedFile(path: string, config) { if (isTmpFile(path)) return true; if (isMatch(path, config.exclude)) return true; if (isHiddenFile(path) && !isMatch(path, config.include)) return true; @@ -34,7 +34,7 @@ export {isTmpFile}; export {isHiddenFile}; export {isExcludedFile}; -export function toDate(date) { +export function toDate(date: string | number | Date) { if (!date || moment.isMoment(date)) return date; if (!(date instanceof Date)) { @@ -46,7 +46,7 @@ export function toDate(date) { return date; } -export function timezone(date, timezone) { +export function timezone(date: Date, timezone: string) { if (moment.isMoment(date)) date = date.toDate(); const offset = date.getTimezoneOffset(); diff --git a/lib/plugins/processor/data.ts b/lib/plugins/processor/data.ts index 7757e7c99c..6db47b3097 100644 --- a/lib/plugins/processor/data.ts +++ b/lib/plugins/processor/data.ts @@ -1,10 +1,12 @@ import { Pattern } from 'hexo-util'; import { extname } from 'path'; +import type Hexo from '../../hexo'; +import type { _File } from '../../box'; -export = ctx => ({ +export = (ctx: Hexo) => ({ pattern: new Pattern('_data/*path'), - process: function dataProcessor(file) { + process: function dataProcessor(file: _File) { const Data = ctx.model('Data'); const { path } = file.params; const id = path.substring(0, path.length - extname(path).length); diff --git a/lib/plugins/processor/post.ts b/lib/plugins/processor/post.ts index 9c61a561b8..c9ec3a1a86 100644 --- a/lib/plugins/processor/post.ts +++ b/lib/plugins/processor/post.ts @@ -5,6 +5,9 @@ import { extname, join } from 'path'; import { stat, listDir } from 'hexo-fs'; import { slugize, Pattern, Permalink } from 'hexo-util'; import { magenta } from 'picocolors'; +import type { _File } from '../../box'; +import type Hexo from '../../hexo'; +import type { Stats } from 'fs'; const postDir = '_posts/'; const draftDir = '_drafts/'; @@ -20,7 +23,7 @@ const preservedKeys = { hash: true }; -export = ctx => { +export = (ctx: Hexo) => { return { pattern: new Pattern(path => { if (isTmpFile(path)) return; @@ -62,7 +65,7 @@ export = ctx => { }; }; -function processPost(ctx, file) { +function processPost(ctx: Hexo, file: _File) { const Post = ctx.model('Post'); const { path } = file.params; const doc = Post.findOne({source: file.path}); @@ -86,7 +89,7 @@ function processPost(ctx, file) { return Promise.all([ file.stat(), file.read() - ]).spread((stats, content) => { + ]).spread((stats: Stats, content: string) => { const data = yfm(content); const info = parseFilename(config.new_post_name, path); const keys = Object.keys(info); @@ -179,7 +182,7 @@ function processPost(ctx, file) { ])); } -function parseFilename(config, path) { +function parseFilename(config: string, path: string) { config = config.substring(0, config.length - extname(config).length); path = path.substring(0, path.length - extname(path).length); @@ -212,7 +215,7 @@ function parseFilename(config, path) { }; } -function scanAssetDir(ctx, post) { +function scanAssetDir(ctx: Hexo, post) { if (!ctx.config.post_asset_folder) return; const assetDir = post.asset_dir; @@ -246,7 +249,7 @@ function scanAssetDir(ctx, post) { }); } -function shouldSkipAsset(ctx, post, asset) { +function shouldSkipAsset(ctx: Hexo, post, asset) { if (!ctx._showDrafts()) { if (post.published === false && asset) { // delete existing draft assets if draft posts are hidden @@ -261,7 +264,7 @@ function shouldSkipAsset(ctx, post, asset) { return asset !== undefined; // skip already existing assets } -function processAsset(ctx, file) { +function processAsset(ctx: Hexo, file: _File) { const PostAsset = ctx.model('PostAsset'); const Post = ctx.model('Post'); const id = file.source.substring(ctx.base_dir.length).replace(/\\/g, '/'); diff --git a/lib/plugins/renderer/json.ts b/lib/plugins/renderer/json.ts index 7c87cf6ecb..c5d02377f9 100644 --- a/lib/plugins/renderer/json.ts +++ b/lib/plugins/renderer/json.ts @@ -1,4 +1,6 @@ -function jsonRenderer(data) { +import type { StoreFunctionData } from '../../extend/renderer'; + +function jsonRenderer(data: StoreFunctionData) { return JSON.parse(data.text); } diff --git a/lib/plugins/renderer/nunjucks.ts b/lib/plugins/renderer/nunjucks.ts index 1ba4ba0205..ccb0281346 100644 --- a/lib/plugins/renderer/nunjucks.ts +++ b/lib/plugins/renderer/nunjucks.ts @@ -1,6 +1,7 @@ -import nunjucks from 'nunjucks'; +import nunjucks, { Environment } from 'nunjucks'; import { readFileSync } from 'hexo-fs'; import { dirname } from 'path'; +import type { StoreFunctionData } from '../../extend/renderer'; function toArray(value) { if (Array.isArray(value)) { @@ -36,13 +37,13 @@ const nunjucksCfg = { lstripBlocks: false }; -const nunjucksAddFilter = env => { +const nunjucksAddFilter = (env: Environment) => { env.addFilter('toarray', toArray); env.addFilter('safedump', safeJsonStringify); }; -function njkCompile(data) { - let env; +function njkCompile(data: StoreFunctionData) { + let env: Environment; if (data.path) { env = nunjucks.configure(dirname(data.path), nunjucksCfg); } else { @@ -52,14 +53,14 @@ function njkCompile(data) { const text = 'text' in data ? data.text : readFileSync(data.path); - return nunjucks.compile(text, env, data.path); + return nunjucks.compile(text as string, env, data.path); } -function njkRenderer(data, locals) { +function njkRenderer(data: StoreFunctionData, locals: object) { return njkCompile(data).render(locals); } -njkRenderer.compile = data => { +njkRenderer.compile = (data: StoreFunctionData) => { // Need a closure to keep the compiled template. return locals => njkCompile(data).render(locals); }; diff --git a/lib/plugins/renderer/plain.ts b/lib/plugins/renderer/plain.ts index e1aa47f2df..99c35a1c1c 100644 --- a/lib/plugins/renderer/plain.ts +++ b/lib/plugins/renderer/plain.ts @@ -1,4 +1,6 @@ -function plainRenderer(data) { +import type { StoreFunctionData } from '../../extend/renderer'; + +function plainRenderer(data: StoreFunctionData) { return data.text; } diff --git a/lib/plugins/renderer/yaml.ts b/lib/plugins/renderer/yaml.ts index a8f0af4a34..fd460d14a0 100644 --- a/lib/plugins/renderer/yaml.ts +++ b/lib/plugins/renderer/yaml.ts @@ -1,6 +1,7 @@ import yaml from 'js-yaml'; import { escape } from 'hexo-front-matter'; import logger from 'hexo-log'; +import type { StoreFunctionData } from '../../extend/renderer'; let schema = {}; // FIXME: workaround for https://github.com/hexojs/hexo/issues/4917 @@ -14,7 +15,7 @@ try { } } -function yamlHelper(data) { +function yamlHelper(data: StoreFunctionData) { return yaml.load(escape(data.text), { schema }); } diff --git a/lib/plugins/tag/asset_img.ts b/lib/plugins/tag/asset_img.ts index e608b499ff..8a9941b74a 100644 --- a/lib/plugins/tag/asset_img.ts +++ b/lib/plugins/tag/asset_img.ts @@ -1,5 +1,6 @@ import img from './img'; import { encodeURL } from 'hexo-util'; +import type Hexo from '../../hexo'; /** * Asset image tag @@ -7,10 +8,10 @@ import { encodeURL } from 'hexo-util'; * Syntax: * {% asset_img [class names] slug [width] [height] [title text [alt text]]%} */ -export = ctx => { +export = (ctx: Hexo) => { const PostAsset = ctx.model('PostAsset'); - return function assetImgTag(args) { + return function assetImgTag(args: string[]) { const len = args.length; // Find image URL diff --git a/lib/plugins/tag/asset_link.ts b/lib/plugins/tag/asset_link.ts index eb07087625..f132730db2 100644 --- a/lib/plugins/tag/asset_link.ts +++ b/lib/plugins/tag/asset_link.ts @@ -1,4 +1,5 @@ import { encodeURL, escapeHTML } from 'hexo-util'; +import type Hexo from '../../hexo'; /** * Asset link tag @@ -6,10 +7,10 @@ import { encodeURL, escapeHTML } from 'hexo-util'; * Syntax: * {% asset_link slug [title] [escape] %} */ -export = ctx => { +export = (ctx: Hexo) => { const PostAsset = ctx.model('PostAsset'); - return function assetLinkTag(args) { + return function assetLinkTag(args: string[]) { const slug = args.shift(); if (!slug) return; diff --git a/lib/plugins/tag/asset_path.ts b/lib/plugins/tag/asset_path.ts index 7242e3ce73..60e4c31746 100644 --- a/lib/plugins/tag/asset_path.ts +++ b/lib/plugins/tag/asset_path.ts @@ -1,4 +1,5 @@ import { encodeURL } from 'hexo-util'; +import type Hexo from '../../hexo'; /** * Asset path tag @@ -6,10 +7,10 @@ import { encodeURL } from 'hexo-util'; * Syntax: * {% asset_path slug %} */ -export = ctx => { +export = (ctx: Hexo) => { const PostAsset = ctx.model('PostAsset'); - return function assetPathTag(args) { + return function assetPathTag(args: string[]) { const slug = args.shift(); if (!slug) return; diff --git a/lib/plugins/tag/blockquote.ts b/lib/plugins/tag/blockquote.ts index 1f99e67c1a..d523e6b994 100644 --- a/lib/plugins/tag/blockquote.ts +++ b/lib/plugins/tag/blockquote.ts @@ -1,6 +1,7 @@ // Based on: https://raw.github.com/imathis/octopress/master/plugins/blockquote.rb import titlecase from 'titlecase'; +import type Hexo from '../../hexo'; const rFullCiteWithTitle = /(\S.*)\s+(https?:\/\/\S+)\s+(.+)/i; const rFullCite = /(\S.*)\s+(https?:\/\/\S+)/i; @@ -10,7 +11,7 @@ const rAuthorTitle = /([^,]+),\s*([^,]+)/; * @param {string[]} args * @param {Hexo} ctx */ -const parseFooter = (args, ctx) => { +const parseFooter = (args: string[], ctx: Hexo) => { const str = args.join(' '); if (!str) return ''; @@ -55,7 +56,7 @@ const parseFooter = (args, ctx) => { * {% endblockquote %} */ -export = ctx => function blockquoteTag(args, content) { +export = (ctx: Hexo) => function blockquoteTag(args: string[], content: string) { const footer = parseFooter(args, ctx); let result = '
'; diff --git a/lib/plugins/tag/code.ts b/lib/plugins/tag/code.ts index 266bda70e2..e56e2122c4 100644 --- a/lib/plugins/tag/code.ts +++ b/lib/plugins/tag/code.ts @@ -1,23 +1,13 @@ // Based on: https://raw.github.com/imathis/octopress/master/plugins/code_block.rb import { escapeHTML } from 'hexo-util'; +import type Hexo from '../../hexo'; +import type { HighlightOptions } from '../../extend/syntax_highlight'; const rCaptionUrlTitle = /(\S[\S\s]*)\s+(https?:\/\/\S+)\s+(.+)/i; const rCaptionUrl = /(\S[\S\s]*)\s+(https?:\/\/\S+)/i; const rCaption = /\S[\S\s]*/; -interface Options { - lang: string; - language_attr: boolean; - firstLine: number; - caption: string; - line_number: boolean; - line_threshold: number; - mark: number[]; - wrap: boolean; - lines_length?: number; -} - /** * Code block tag * Syntax: @@ -37,11 +27,11 @@ interface Options { * @returns {String} Code snippet with code highlighting */ -function parseArgs(args): Options { +function parseArgs(args: string[]): HighlightOptions { const _else = []; const len = args.length; - let lang, language_attr, - line_number, line_threshold, wrap; + let lang: string, language_attr: boolean, + line_number: boolean, line_threshold: number, wrap: boolean; let firstLine = 1; const mark = []; for (let i = 0; i < len; i++) { @@ -63,10 +53,10 @@ function parseArgs(args): Options { line_number = value === 'true'; break; case 'line_threshold': - if (!isNaN(value)) line_threshold = +value; + if (!isNaN(Number(value))) line_threshold = +value; break; case 'first_line': - if (!isNaN(value)) firstLine = +value; + if (!isNaN(Number(value))) firstLine = +value; break; case 'wrap': wrap = value === 'true'; @@ -88,7 +78,7 @@ function parseArgs(args): Options { mark.push(a); } } - if (!isNaN(cur)) mark.push(+cur); + if (!isNaN(Number(cur))) mark.push(+cur); } break; } @@ -126,14 +116,14 @@ function parseArgs(args): Options { }; } -export = ctx => function codeTag(args, content) { +export = (ctx: Hexo) => function codeTag(args: string[], content: string) { // If neither highlight.js nor prism.js is enabled, return escaped code directly if (!ctx.extend.highlight.query(ctx.config.syntax_highlighter)) { return `
${escapeHTML(content)}
`; } - let index; + let index: number; let enableHighlight = true; if ((index = args.findIndex(item => item.startsWith('highlight:'))) !== -1) { diff --git a/lib/plugins/tag/full_url_for.ts b/lib/plugins/tag/full_url_for.ts index 6dd2ff76b8..887b2f07c7 100644 --- a/lib/plugins/tag/full_url_for.ts +++ b/lib/plugins/tag/full_url_for.ts @@ -1,4 +1,5 @@ import { full_url_for, htmlTag } from 'hexo-util'; +import type Hexo from '../../hexo'; /** * Full url for tag @@ -6,7 +7,7 @@ import { full_url_for, htmlTag } from 'hexo-util'; * Syntax: * {% full_url_for text path %} */ -export = ctx => { +export = (ctx: Hexo) => { return function fullUrlForTag([text, path]) { const url = full_url_for.call(ctx, path); const attrs = { diff --git a/lib/plugins/tag/iframe.ts b/lib/plugins/tag/iframe.ts index f1e6b2663d..9597a809a7 100644 --- a/lib/plugins/tag/iframe.ts +++ b/lib/plugins/tag/iframe.ts @@ -7,7 +7,7 @@ import { htmlTag } from 'hexo-util'; * {% iframe url [width] [height] %} */ -function iframeTag(args) { +function iframeTag(args: string[]) { const src = args[0]; const width = args[1] && args[1] !== 'default' ? args[1] : '100%'; const height = args[2] && args[2] !== 'default' ? args[2] : '300'; diff --git a/lib/plugins/tag/img.ts b/lib/plugins/tag/img.ts index 22e4970020..2e8b1c8d29 100644 --- a/lib/plugins/tag/img.ts +++ b/lib/plugins/tag/img.ts @@ -1,4 +1,5 @@ import { htmlTag, url_for } from 'hexo-util'; +import type Hexo from '../../hexo'; const rUrl = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[.!/\\w]*))?)/; const rMetaDoubleQuote = /"?([^"]+)?"?/; @@ -10,9 +11,9 @@ const rMetaSingleQuote = /'?([^']+)?'?/; * Syntax: * {% img [class names] /path/to/image [width] [height] [title text [alt text]] %} */ -export = ctx => { +export = (ctx: Hexo) => { - return function imgTag(args) { + return function imgTag(args: string[]) { const classes = []; let src, width, height, title, alt; diff --git a/lib/plugins/tag/include_code.ts b/lib/plugins/tag/include_code.ts index 8457c75294..78edbe1bdb 100644 --- a/lib/plugins/tag/include_code.ts +++ b/lib/plugins/tag/include_code.ts @@ -1,5 +1,6 @@ import { exists, readFile } from 'hexo-fs'; import { basename, extname, join, posix } from 'path'; +import type Hexo from '../../hexo'; const rCaptionTitleFile = /(.*)?(?:\s+|^)(\/*\S+)/; const rLang = /\s*lang:(\w+)/i; @@ -13,7 +14,7 @@ const rTo = /\s*to:(\d+)/i; * {% include_code [title] [lang:language] path/to/file %} */ -export = ctx => function includeCodeTag(args) { +export = (ctx: Hexo) => function includeCodeTag(args: string[]) { let codeDir = ctx.config.code_dir; let arg = args.join(' '); diff --git a/lib/plugins/tag/index.ts b/lib/plugins/tag/index.ts index b2306d36e4..8f3d303db2 100644 --- a/lib/plugins/tag/index.ts +++ b/lib/plugins/tag/index.ts @@ -52,7 +52,7 @@ export default (ctx: Hexo) => { // Use WeakMap to track different ctx (in case there is any) const moized = new WeakMap(); -export function postFindOneFactory(ctx) { +export function postFindOneFactory(ctx: Hexo) { if (moized.has(ctx)) { return moized.get(ctx); } @@ -66,7 +66,7 @@ export function postFindOneFactory(ctx) { return moizedPostFindOne; } -function createPostFindOne(ctx) { +function createPostFindOne(ctx: Hexo) { const Post = ctx.model('Post'); return Post.findOne.bind(Post); } diff --git a/lib/plugins/tag/link.ts b/lib/plugins/tag/link.ts index 0df202b574..b0afbacfcd 100644 --- a/lib/plugins/tag/link.ts +++ b/lib/plugins/tag/link.ts @@ -9,7 +9,7 @@ const rUrl = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:ww * {% link text url [external] [title] %} */ -function linkTag(args, content) { +function linkTag(args: string[]) { let url = ''; const text = []; let external = false; diff --git a/lib/plugins/tag/post_link.ts b/lib/plugins/tag/post_link.ts index 782714a1d2..577b1319ef 100644 --- a/lib/plugins/tag/post_link.ts +++ b/lib/plugins/tag/post_link.ts @@ -1,5 +1,6 @@ import { encodeURL, escapeHTML } from 'hexo-util'; import { postFindOneFactory } from './'; +import type Hexo from '../../hexo'; /** * Post link tag @@ -7,8 +8,8 @@ import { postFindOneFactory } from './'; * Syntax: * {% post_link slug | title [title] [escape] %} */ -export = ctx => { - return function postLinkTag(args) { +export = (ctx: Hexo) => { + return function postLinkTag(args: string[]) { const slug = args.shift(); if (!slug) { throw new Error(`Post not found: "${slug}" doesn't exist for {% post_link %}`); diff --git a/lib/plugins/tag/post_path.ts b/lib/plugins/tag/post_path.ts index e9aec212f2..fdc33eccab 100644 --- a/lib/plugins/tag/post_path.ts +++ b/lib/plugins/tag/post_path.ts @@ -1,5 +1,6 @@ import { encodeURL } from 'hexo-util'; import { postFindOneFactory } from './'; +import type Hexo from '../../hexo'; /** * Post path tag @@ -7,8 +8,8 @@ import { postFindOneFactory } from './'; * Syntax: * {% post_path slug | title %} */ -export = ctx => { - return function postPathTag(args) { +export = (ctx: Hexo) => { + return function postPathTag(args: any[]) { const slug = args.shift(); if (!slug) return; diff --git a/lib/plugins/tag/pullquote.ts b/lib/plugins/tag/pullquote.ts index 1235a26d9e..89bf01697a 100644 --- a/lib/plugins/tag/pullquote.ts +++ b/lib/plugins/tag/pullquote.ts @@ -1,3 +1,5 @@ +import type Hexo from '../../hexo'; + /** * Pullquote tag * @@ -6,7 +8,7 @@ * Quote string * {% endpullquote %} */ -export = ctx => function pullquoteTag(args, content) { +export = (ctx: Hexo) => function pullquoteTag(args: string[], content: string) { args.unshift('pullquote'); const result = ctx.render.renderSync({text: content, engine: 'markdown'}); diff --git a/lib/plugins/tag/url_for.ts b/lib/plugins/tag/url_for.ts index 6fb3750886..a417fa6219 100644 --- a/lib/plugins/tag/url_for.ts +++ b/lib/plugins/tag/url_for.ts @@ -1,4 +1,5 @@ import { url_for, htmlTag } from 'hexo-util'; +import type Hexo from '../../hexo'; /** * Url for tag @@ -6,7 +7,7 @@ import { url_for, htmlTag } from 'hexo-util'; * Syntax: * {% url_for text path [relative] %} */ -export = ctx => { +export = (ctx: Hexo) => { return function urlForTag([text, path, relative]) { const url = url_for.call(ctx, path, relative ? { relative: relative !== 'false' } : undefined); const attrs = { diff --git a/lib/theme/index.ts b/lib/theme/index.ts index d37cd281b5..aff5a74711 100644 --- a/lib/theme/index.ts +++ b/lib/theme/index.ts @@ -6,14 +6,16 @@ import { config } from './processors/config'; import { i18n } from './processors/i18n'; import { source } from './processors/source'; import { view } from './processors/view'; +import type Hexo from '../hexo'; class Theme extends Box { public config: any; public views: any; - public i18n: any; + public i18n: I18n; public View: any; + public processors: any[]; - constructor(ctx, options?) { + constructor(ctx: Hexo, options?) { super(ctx, ctx.theme_dir, options); this.config = {}; @@ -46,7 +48,7 @@ class Theme extends Box { _View.prototype._helper = ctx.extend.helper; } - getView(path) { + getView(path: string) { // Replace backslashes on Windows path = path.replace(/\\/g, '/'); @@ -63,7 +65,7 @@ class Theme extends Box { return views[Object.keys(views)[0]]; } - setView(path, data) { + setView(path: string, data) { const ext = extname(path); const name = path.substring(0, path.length - ext.length); this.views[name] = this.views[name] || {}; @@ -72,7 +74,7 @@ class Theme extends Box { views[ext] = new this.View(path, data); } - removeView(path) { + removeView(path: string) { const ext = extname(path); const name = path.substring(0, path.length - ext.length); const views = this.views[name]; diff --git a/lib/theme/processors/config.ts b/lib/theme/processors/config.ts index 64f65e2c28..c37f3ed13a 100644 --- a/lib/theme/processors/config.ts +++ b/lib/theme/processors/config.ts @@ -1,13 +1,15 @@ import { Pattern } from 'hexo-util'; +import type { _File } from '../../box'; +import Theme from '..'; -function process(file) { +function process(file: _File) { if (file.type === 'delete') { - file.box.config = {}; + (file.box as Theme).config = {}; return; } return file.render().then(result => { - file.box.config = result; + (file.box as Theme).config = result; this.log.debug('Theme config loaded.'); }).catch(err => { this.log.error('Theme config load failed.'); diff --git a/lib/theme/processors/i18n.ts b/lib/theme/processors/i18n.ts index ce955eb8a4..af2db9be95 100644 --- a/lib/theme/processors/i18n.ts +++ b/lib/theme/processors/i18n.ts @@ -1,11 +1,13 @@ import { Pattern } from 'hexo-util'; import { extname } from 'path'; +import type { _File } from '../../box'; +import type Theme from '..'; -function process(file) { +function process(file: _File) { const { path } = file.params; const ext = extname(path); const name = path.substring(0, path.length - ext.length); - const { i18n } = file.box; + const { i18n } = (file.box as Theme); if (file.type === 'delete') { i18n.remove(name); diff --git a/lib/theme/processors/source.ts b/lib/theme/processors/source.ts index 40915fae47..ac8c21a1fe 100644 --- a/lib/theme/processors/source.ts +++ b/lib/theme/processors/source.ts @@ -1,7 +1,8 @@ import { Pattern } from 'hexo-util'; import * as common from '../../plugins/processor/common'; +import type { _File } from '../../box'; -function process(file) { +function process(file: _File) { const Asset = this.model('Asset'); const id = file.source.substring(this.base_dir.length).replace(/\\/g, '/'); const { path } = file.params; diff --git a/lib/theme/processors/view.ts b/lib/theme/processors/view.ts index c4011564e2..c127d02e7c 100644 --- a/lib/theme/processors/view.ts +++ b/lib/theme/processors/view.ts @@ -1,15 +1,17 @@ import { Pattern } from 'hexo-util'; +import type { _File } from '../../box'; +import type Theme from '..'; -function process(file) { +function process(file: _File) { const { path } = file.params; if (file.type === 'delete') { - file.box.removeView(path); + (file.box as Theme).removeView(path); return; } return file.read().then(result => { - file.box.setView(path, result); + (file.box as Theme).setView(path, result); }); } diff --git a/lib/theme/view.ts b/lib/theme/view.ts index f2b2234d4f..af4c75be62 100644 --- a/lib/theme/view.ts +++ b/lib/theme/view.ts @@ -1,8 +1,10 @@ import { dirname, extname, join } from 'path'; import { parse as yfm } from 'hexo-front-matter'; import Promise from 'bluebird'; +import type Theme from '.'; +import type Render from '../hexo/render'; -const assignIn = (target, ...sources) => { +const assignIn = (target: any, ...sources: any[]) => { const length = sources.length; if (length < 1 || target == null) return target; @@ -21,18 +23,16 @@ class Options { } class View { - public path: any; + public path: string; public source: any; - public _theme: any; + public _theme: Theme; public data: any; public _compiled: any; public _compiledSync: any; public _helper: any; - public _render: any; - public layout: any; - public _content: any; + public _render: Render; - constructor(path, data) { + constructor(path: string, data) { this.path = path; this.source = join(this._theme.base, 'layout', path); this.data = typeof data === 'string' ? yfm(data) : data; @@ -106,7 +106,7 @@ class View { return locals; } - _resolveLayout(name) { + _resolveLayout(name: string) { // Relative path const layoutPath = join(dirname(this.path), name); let layoutView = this._theme.getView(layoutPath); @@ -128,7 +128,7 @@ class View { text: this.data._content }; - function buildFilterArguments(result) { + function buildFilterArguments(result: any): [string, any, any] { const output = render.getOutput(ext) || ext; return [ `after_render:${output}`, diff --git a/lib/types.ts b/lib/types.ts new file mode 100644 index 0000000000..ea6313c253 --- /dev/null +++ b/lib/types.ts @@ -0,0 +1 @@ +type NodeJSLikeCallback = (err: E, result?: R) => void diff --git a/package.json b/package.json index a9681ab722..f9cfc7ad34 100644 --- a/package.json +++ b/package.json @@ -66,12 +66,13 @@ "warehouse": "^5.0.0" }, "devDependencies": { - "0x": "^5.1.2", "@types/bluebird": "^3.5.37", "@types/node": "^18.11.8", "@types/nunjucks": "^3.2.2", + "@types/text-table": "^0.2.4", "@typescript-eslint/eslint-plugin": "^5.41.0", "@typescript-eslint/parser": "^5.41.0", + "0x": "^5.1.2", "c8": "^8.0.0", "chai": "^4.3.6", "cheerio": "0.22.0", diff --git a/test/scripts/box/box.js b/test/scripts/box/box.js index 71548cceeb..4aaebd8698 100644 --- a/test/scripts/box/box.js +++ b/test/scripts/box/box.js @@ -9,7 +9,7 @@ const { spy, match, assert: sinonAssert } = require('sinon'); describe('Box', () => { const Hexo = require('../../../dist/hexo'); const baseDir = join(__dirname, 'box_tmp'); - const Box = require('../../../dist/box'); + const Box = require('../../../dist/box').default; const newBox = (path, config) => { const hexo = new Hexo(baseDir, { silent: true }); diff --git a/test/scripts/box/file.js b/test/scripts/box/file.js index e019d913cc..f2fe533b4c 100644 --- a/test/scripts/box/file.js +++ b/test/scripts/box/file.js @@ -7,7 +7,7 @@ const { load } = require('js-yaml'); describe('File', () => { const Hexo = require('../../../dist/hexo'); const hexo = new Hexo(__dirname); - const Box = require('../../../dist/box'); + const Box = require('../../../dist/box').default; const box = new Box(hexo, join(hexo.base_dir, 'file_test')); const { File } = box; diff --git a/test/scripts/extend/renderer.js b/test/scripts/extend/renderer.js index 44327d0cb7..8cb8131251 100644 --- a/test/scripts/extend/renderer.js +++ b/test/scripts/extend/renderer.js @@ -1,7 +1,7 @@ 'use strict'; describe('Renderer', () => { - const Renderer = require('../../../dist/extend/renderer'); + const Renderer = require('../../../dist/extend/renderer').default; it('register()', () => { const r = new Renderer(); From d56529d24a1ca6f5711edd38b670a898c53a9b62 Mon Sep 17 00:00:00 2001 From: Uiolee <22849383+uiolee@users.noreply.github.com> Date: Tue, 31 Oct 2023 21:23:14 +0800 Subject: [PATCH 18/24] chore(deps): bump hexo-front-matter from 4.0.0 to ^4.2.1 (#5336) Co-authored-by: yoshinorin --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f9cfc7ad34..b5e2622472 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "archy": "^1.0.0", "bluebird": "^3.7.2", "hexo-cli": "^4.3.0", - "hexo-front-matter": "4.0.0", + "hexo-front-matter": "^4.2.1", "hexo-fs": "^4.1.1", "hexo-i18n": "^2.0.0", "hexo-log": "^4.0.1", From f7a581ea17e7e86d85c79d5696389734e9cb3799 Mon Sep 17 00:00:00 2001 From: yoshinorin Date: Tue, 31 Oct 2023 22:31:54 +0900 Subject: [PATCH 19/24] release: v7.0.0 (#5329) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b5e2622472..8790841a89 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hexo", - "version": "7.0.0-rc2", + "version": "7.0.0", "description": "A fast, simple & powerful blog framework, powered by Node.js.", "main": "dist/hexo", "bin": { From d2cc93154dffddfcfe7018efc5e2cfed378487ea Mon Sep 17 00:00:00 2001 From: yoshinorin Date: Thu, 2 Nov 2023 20:03:28 +0900 Subject: [PATCH 20/24] fix(types): cast from `number` to `string` explicitly (#5342) - fix `TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.` error --- lib/hexo/multi_config_path.ts | 2 +- lib/plugins/console/generate.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/hexo/multi_config_path.ts b/lib/hexo/multi_config_path.ts index 978c04fca0..7402657e90 100644 --- a/lib/hexo/multi_config_path.ts +++ b/lib/hexo/multi_config_path.ts @@ -62,7 +62,7 @@ export = (ctx: Hexo) => function multiConfigPath(base: string, configPaths: stri return defaultPath; } - log.i('Config based on', count, 'files'); + log.i('Config based on', count.toString(), 'files'); const multiconfigRoot = outputDir || base; const outputPath = join(multiconfigRoot, '_multiconfig.yml'); diff --git a/lib/plugins/console/generate.ts b/lib/plugins/console/generate.ts index 2b17697b49..c91b45e2d3 100644 --- a/lib/plugins/console/generate.ts +++ b/lib/plugins/console/generate.ts @@ -169,7 +169,7 @@ class Generater { const interval = prettyHrtime(process.hrtime(this.start)); const count = result.filter(Boolean).length; - log.info('%d files generated in %s', count, cyan(interval)); + log.info('%d files generated in %s', count.toString(), cyan(interval)); }); } execWatch(): Promise { From bdf3cf2693a691dd438fa76d9fcd025f2852a455 Mon Sep 17 00:00:00 2001 From: Uiolee <22849383+uiolee@users.noreply.github.com> Date: Thu, 2 Nov 2023 23:57:26 +0800 Subject: [PATCH 21/24] ci(benchmark): add PR permissions for comment (#5334) --- .github/workflows/benchmark.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index a822f5f5dc..5d27c7401b 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -3,12 +3,12 @@ name: Benchmark on: push: paths: - - 'lib/**' + - "lib/**" pull_request: branches: - master paths-ignore: - - 'test/scripts/**' + - "test/scripts/**" jobs: benchmark: @@ -16,7 +16,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - node-version: ['14', '16', '18'] + node-version: ["14", "16", "18"] fail-fast: false steps: - uses: actions/checkout@v4 @@ -30,10 +30,12 @@ jobs: run: node test/benchmark.js --benchmark profiling: runs-on: ${{ matrix.os }} + permissions: + pull-requests: write # for marocchino/sticky-pull-request-comment to create or update PR comment strategy: matrix: os: [ubuntu-latest] - node-version: ['14', '16', '18'] + node-version: ["14", "16", "18"] fail-fast: false steps: - uses: actions/checkout@v4 From 9ceff5e306e3cf1aa99142f466816ea74a8cbbc1 Mon Sep 17 00:00:00 2001 From: Uiolee <22849383+uiolee@users.noreply.github.com> Date: Wed, 8 Nov 2023 00:35:26 +0800 Subject: [PATCH 22/24] chore(deps-dev): remove @ts/eslint-plugin, parser (#5290) --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index 8790841a89..a7b9c45349 100644 --- a/package.json +++ b/package.json @@ -70,8 +70,6 @@ "@types/node": "^18.11.8", "@types/nunjucks": "^3.2.2", "@types/text-table": "^0.2.4", - "@typescript-eslint/eslint-plugin": "^5.41.0", - "@typescript-eslint/parser": "^5.41.0", "0x": "^5.1.2", "c8": "^8.0.0", "chai": "^4.3.6", From 486de57341eda9878416d0f975dbb260236f0c7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 26 Nov 2023 17:27:00 +0900 Subject: [PATCH 23/24] chore: bump typescript from 4.9.5 to 5.3.2 (#5358) Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.9.5 to 5.3.2. - [Release notes](https://github.com/Microsoft/TypeScript/releases) - [Commits](https://github.com/Microsoft/TypeScript/compare/v4.9.5...v5.3.2) --- updated-dependencies: - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a7b9c45349..f48e32b70d 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "mocha": "^10.0.0", "sinon": "^15.0.0", "ts-node": "^10.9.1", - "typescript": "^4.8.4" + "typescript": "^5.3.2" }, "engines": { "node": ">=14" From ea4f63cd2a7a6712acb8a15fc36692d8ef52a64b Mon Sep 17 00:00:00 2001 From: Ilia Yatsenko Date: Sat, 2 Dec 2023 15:46:00 +0200 Subject: [PATCH 24/24] added URL hash support for post_link tag (#5356) --- lib/plugins/tag/post_link.ts | 13 +++++++++++-- test/scripts/tags/post_link.js | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/plugins/tag/post_link.ts b/lib/plugins/tag/post_link.ts index 577b1319ef..67289df469 100644 --- a/lib/plugins/tag/post_link.ts +++ b/lib/plugins/tag/post_link.ts @@ -10,11 +10,19 @@ import type Hexo from '../../hexo'; */ export = (ctx: Hexo) => { return function postLinkTag(args: string[]) { - const slug = args.shift(); + let slug = args.shift(); if (!slug) { throw new Error(`Post not found: "${slug}" doesn't exist for {% post_link %}`); } + let hash = ''; + const parts = slug.split('#'); + + if (parts.length === 2) { + slug = parts[0]; + hash = parts[1]; + } + let escape = args[args.length - 1]; if (escape === 'true' || escape === 'false') { args.pop(); @@ -33,7 +41,8 @@ export = (ctx: Hexo) => { const attrTitle = escapeHTML(post.title || post.slug); if (escape === 'true') title = escapeHTML(title); - const link = encodeURL(new URL(post.path, ctx.config.url).pathname); + const url = new URL(post.path, ctx.config.url).pathname + (hash ? `#${hash}` : ''); + const link = encodeURL(url); return `${title}`; }; diff --git a/test/scripts/tags/post_link.js b/test/scripts/tags/post_link.js index 999f2cad48..05839a8098 100644 --- a/test/scripts/tags/post_link.js +++ b/test/scripts/tags/post_link.js @@ -73,4 +73,8 @@ describe('post_link', () => { it('should throw if post not found', () => { should.throw(() => postLink(['bar']), Error, /Post not found: post_link bar\./); }); + + it('should keep hash', () => { + postLink(['foo#bar']).should.eql('Hello world'); + }); });