Skip to content

Commit 8c5d506

Browse files
stevenjoezhangyoshinorin
andauthoredNov 9, 2022
refactor: migrate typescript (#418)
Co-authored-by: yoshinorin <yoshinorin.net@outlook.com>
1 parent 6d722a2 commit 8c5d506

23 files changed

+676
-229
lines changed
 

‎.eslintignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
node_modules/
22
coverage/
33
tmp/
4-
assets/
4+
assets/
5+
dist/

‎.eslintrc.json

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
{
2-
"extends": "hexo",
3-
"root": true
2+
"root": true,
3+
"extends": "hexo/ts.js",
4+
"parserOptions": {
5+
"sourceType": "module",
6+
"ecmaVersion": 2020
7+
},
8+
"rules": {
9+
"@typescript-eslint/no-var-requires": 0
10+
}
411
}

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ tmp/
55
.idea/
66
.nyc_output/
77
.vscode/
8+
dist/

‎lib/console/help.js ‎lib/console/help.ts

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
'use strict';
2-
3-
const { underline, bold } = require('picocolors');
4-
const { readFile } = require('hexo-fs');
5-
const { join } = require('path');
6-
const Promise = require('bluebird');
1+
import { underline, bold } from 'picocolors';
2+
import { readFile } from 'hexo-fs';
3+
import { join } from 'path';
4+
import Promise from 'bluebird';
75

86
const COMPLETION_DIR = join(__dirname, '../../completion');
97

@@ -115,4 +113,4 @@ function printCompletion(type) {
115113
});
116114
}
117115

118-
module.exports = helpConsole;
116+
export = helpConsole;
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
'use strict';
1+
import helpConsole from './help';
2+
import initConsole from './init';
3+
import versionConsole from './version';
24

3-
module.exports = function(ctx) {
5+
export = function(ctx) {
46
const { console } = ctx.extend;
57

6-
console.register('help', 'Get help on a command.', {}, require('./help'));
8+
console.register('help', 'Get help on a command.', {}, helpConsole);
79

810
console.register('init', 'Create a new Hexo folder.', {
911
desc: 'Create a new Hexo folder at the specified path or the current directory.',
@@ -15,7 +17,7 @@ module.exports = function(ctx) {
1517
{name: '--no-clone', desc: 'Copy files instead of cloning from GitHub'},
1618
{name: '--no-install', desc: 'Skip npm install'}
1719
]
18-
}, require('./init'));
20+
}, initConsole);
1921

20-
console.register('version', 'Display version information.', {}, require('./version'));
22+
console.register('version', 'Display version information.', {}, versionConsole);
2123
};

‎lib/console/init.js ‎lib/console/init.ts

+10-12
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
'use strict';
2-
3-
const Promise = require('bluebird');
4-
const { join, resolve } = require('path');
5-
const { magenta } = require('picocolors');
6-
const { existsSync, readdirSync, rmdir, unlink, copyDir, readdir, stat } = require('hexo-fs');
7-
const tildify = require('tildify');
8-
const { spawn } = require('hexo-util');
9-
const commandExistsSync = require('command-exists').sync;
1+
import BlueBirdPromise from 'bluebird';
2+
import { join, resolve } from 'path';
3+
import { magenta } from 'picocolors';
4+
import { existsSync, readdirSync, rmdir, unlink, copyDir, readdir, stat } from 'hexo-fs';
5+
import tildify from 'tildify';
6+
import { spawn } from 'hexo-util';
7+
import { sync as commandExistsSync } from 'command-exists';
108

119
const ASSET_DIR = join(__dirname, '../../assets');
1210
const GIT_REPO_URL = 'https://github.com/hexojs/hexo-starter.git';
@@ -20,7 +18,7 @@ async function initConsole(args) {
2018

2119
if (existsSync(target) && readdirSync(target).length !== 0) {
2220
log.fatal(`${magenta(tildify(target))} not empty, please run \`hexo init\` on an empty folder and then copy your files into it`);
23-
await Promise.reject(new Error('target not empty'));
21+
await BlueBirdPromise.reject(new Error('target not empty'));
2422
}
2523

2624
log.info('Cloning hexo-starter', GIT_REPO_URL);
@@ -38,7 +36,7 @@ async function initConsole(args) {
3836
await copyAsset(target);
3937
}
4038

41-
await Promise.all([
39+
await BlueBirdPromise.all([
4240
removeGitDir(target),
4341
removeGitModules(target)
4442
]);
@@ -111,4 +109,4 @@ async function removeGitModules(target) {
111109
}
112110
}
113111

114-
module.exports = initConsole;
112+
export = initConsole;

‎lib/console/version.js ‎lib/console/version.ts

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
'use strict';
2-
3-
const os = require('os');
1+
import os from 'os';
42
const pkg = require('../../package.json');
5-
const Promise = require('bluebird');
6-
const { spawn } = require('hexo-util');
3+
import BlueBirdPromise from 'bluebird';
4+
import { spawn } from 'hexo-util';
75

8-
async function versionConsole(args) {
6+
async function versionConsole() {
97
const { versions, platform } = process;
108
const keys = Object.keys(versions);
119

@@ -33,7 +31,7 @@ async function versionConsole(args) {
3331
console.log('%s: %s', key, versions[key]);
3432
}
3533

36-
await Promise.resolve();
34+
await BlueBirdPromise.resolve();
3735
}
3836

39-
module.exports = versionConsole;
37+
export = versionConsole;

‎lib/context.js ‎lib/context.ts

+19-11
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
'use strict';
2-
3-
const logger = require('hexo-log');
4-
const { underline } = require('picocolors');
5-
const { EventEmitter } = require('events');
6-
const Promise = require('bluebird');
7-
const ConsoleExtend = require('./extend/console');
1+
import logger from 'hexo-log';
2+
import { underline } from 'picocolors';
3+
import { EventEmitter } from 'events';
4+
import Promise from 'bluebird';
5+
import ConsoleExtend from './extend/console';
86

97
// a stub Hexo object
108
// see `hexojs/hexo/lib/hexo/index.js`
119

10+
type Callback = (err?: any, value?: any) => void;
11+
1212
class Context extends EventEmitter {
13+
base_dir: string;
14+
log: logger;
15+
extend: {
16+
console: ConsoleExtend;
17+
};
18+
1319
constructor(base = process.cwd(), args = {}) {
1420
super();
1521
this.base_dir = base;
@@ -24,9 +30,11 @@ class Context extends EventEmitter {
2430
// Do nothing
2531
}
2632

27-
call(name, args, callback) {
33+
call(name: string, args: object, callback: Callback);
34+
call(name: string, callback?: Callback);
35+
call(name: string, args?: object | Callback, callback?: Callback) {
2836
if (!callback && typeof args === 'function') {
29-
callback = args;
37+
callback = args as Callback;
3038
args = {};
3139
}
3240

@@ -41,7 +49,7 @@ class Context extends EventEmitter {
4149
}).asCallback(callback);
4250
}
4351

44-
exit(err) {
52+
exit(err?: Error) {
4553
if (err) {
4654
this.log.fatal(
4755
{err},
@@ -58,4 +66,4 @@ class Context extends EventEmitter {
5866
}
5967
}
6068

61-
module.exports = Context;
69+
export = Context;

‎lib/extend/console.js ‎lib/extend/console.ts

+28-9
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
1-
'use strict';
1+
import Promise from 'bluebird';
2+
import abbrev from 'abbrev';
23

3-
const Promise = require('bluebird');
4-
const abbrev = require('abbrev');
4+
interface Callback {
5+
(args?: object): any;
6+
options?: object;
7+
desc?: string;
8+
}
9+
10+
interface Store {
11+
[key: string]: Callback;
12+
}
13+
14+
interface Alias {
15+
[key: string]: string;
16+
}
517

618
class Console {
19+
store: Store;
20+
alias: Alias;
21+
722
constructor() {
823
this.store = {};
924
this.alias = {};
1025
}
1126

12-
get(name) {
27+
get(name: string) {
1328
name = name.toLowerCase();
1429
return this.store[this.alias[name]];
1530
}
@@ -18,13 +33,17 @@ class Console {
1833
return this.store;
1934
}
2035

21-
register(name, desc, options, fn) {
36+
register(name: string, desc: string, options: object, fn: Callback): void;
37+
register(name: string, options: object, fn: Callback): void;
38+
register(name: string, desc: string, fn: Callback): void;
39+
register(name: string, fn: Callback): void;
40+
register(name: string, desc: string | object | Callback, options?: object | Callback, fn?: Callback) {
2241
if (!name) throw new TypeError('name is required');
2342

2443
if (!fn) {
2544
if (options) {
2645
if (typeof options === 'function') {
27-
fn = options;
46+
fn = options as Callback;
2847

2948
if (typeof desc === 'object') { // name, options, fn
3049
options = desc;
@@ -38,7 +57,7 @@ class Console {
3857
} else {
3958
// name, fn
4059
if (typeof desc === 'function') {
41-
fn = desc;
60+
fn = desc as Callback;
4261
options = {};
4362
desc = '';
4463
} else {
@@ -56,10 +75,10 @@ class Console {
5675
this.store[name.toLowerCase()] = fn;
5776
const c = fn;
5877
c.options = options;
59-
c.desc = desc;
78+
c.desc = desc as string;
6079

6180
this.alias = abbrev(Object.keys(this.store));
6281
}
6382
}
6483

65-
module.exports = Console;
84+
export = Console;

‎lib/find_pkg.js ‎lib/find_pkg.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
1-
'use strict';
1+
import { resolve, join, dirname } from 'path';
2+
import { readFile } from 'hexo-fs';
23

3-
const { resolve, join, dirname } = require('path');
4-
const { readFile } = require('hexo-fs');
4+
interface findPkgArgs {
5+
cwd?: string;
6+
}
57

6-
function findPkg(cwd, args = {}) {
8+
function findPkg(cwd: string, args: findPkgArgs = {}) {
79
if (args.cwd) {
810
cwd = resolve(cwd, args.cwd);
911
}
1012

1113
return checkPkg(cwd);
1214
}
1315

14-
function checkPkg(path) {
16+
function checkPkg(path: string) {
1517
const pkgPath = join(path, 'package.json');
1618

1719
return readFile(pkgPath).then(content => {
18-
const json = JSON.parse(content);
20+
const json = JSON.parse(content as string);
1921
if (typeof json.hexo === 'object') return path;
2022
}).catch(err => {
2123
if (err && err.code === 'ENOENT') {
@@ -29,4 +31,4 @@ function checkPkg(path) {
2931
});
3032
}
3133

32-
module.exports = findPkg;
34+
export = findPkg;

‎lib/goodbye.js ‎lib/goodbye.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
'use strict';
2-
31
const byeWords = [
42
'Good bye',
53
'See you again',
@@ -9,4 +7,4 @@ const byeWords = [
97
'Catch you later'
108
];
119

12-
module.exports = () => byeWords[(Math.random() * byeWords.length) | 0];
10+
export = () => byeWords[(Math.random() * byeWords.length) | 0];

‎lib/hexo.js ‎lib/hexo.ts

+19-17
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
'use strict';
2-
3-
const { magenta } = require('picocolors');
4-
const tildify = require('tildify');
5-
const Promise = require('bluebird');
6-
const Context = require('./context');
7-
const findPkg = require('./find_pkg');
8-
const goodbye = require('./goodbye');
9-
const minimist = require('minimist');
10-
const resolve = require('resolve');
11-
const { camelCaseKeys } = require('hexo-util');
1+
import { magenta } from 'picocolors';
2+
import tildify from 'tildify';
3+
import Promise from 'bluebird';
4+
import Context from './context';
5+
import findPkg from './find_pkg';
6+
import goodbye from './goodbye';
7+
import minimist from 'minimist';
8+
import resolve from 'resolve';
9+
import { camelCaseKeys } from 'hexo-util';
10+
import registerConsole from './console';
11+
import helpConsole from './console/help';
12+
import initConsole from './console/init';
13+
import versionConsole from './console/version';
1214

1315
class HexoNotFoundError extends Error {}
1416

@@ -44,7 +46,7 @@ function entry(cwd = process.cwd(), args) {
4446
if (mod) hexo = mod;
4547
log = hexo.log;
4648

47-
require('./console')(hexo);
49+
registerConsole(hexo);
4850

4951
return hexo.init();
5052
}).then(() => {
@@ -65,12 +67,12 @@ function entry(cwd = process.cwd(), args) {
6567
}
6668

6769
entry.console = {
68-
init: require('./console/init'),
69-
help: require('./console/help'),
70-
version: require('./console/version')
70+
init: initConsole,
71+
help: helpConsole,
72+
version: versionConsole
7173
};
7274

73-
entry.version = require('../package.json').version;
75+
entry.version = require('../package.json').version as string;
7476

7577
function loadModule(path, args) {
7678
return Promise.try(() => {
@@ -93,4 +95,4 @@ function watchSignal(hexo) {
9395
});
9496
}
9597

96-
module.exports = entry;
98+
export = entry;

‎package-lock.json

+508-128
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+15-4
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,19 @@
77
"hexo": "./bin/hexo"
88
},
99
"files": [
10-
"lib",
10+
"dist/**",
1111
"completion",
1212
"bin",
1313
"assets"
1414
],
15+
"types": "./dist/hexo.d.ts",
1516
"scripts": {
17+
"prepublish ": "npm install && npm run clean && npm run build",
18+
"build": "tsc -b",
19+
"clean": "tsc -b --clean",
1620
"eslint": "eslint .",
17-
"test": "mocha test/index.js",
21+
"pretest": "npm run clean && npm run build",
22+
"test": "mocha test/index.js --require ts-node/register",
1823
"test-cov": "nyc --reporter=lcovonly npm test",
1924
"prepare": "git submodule init && git submodule update && git submodule foreach git pull origin master"
2025
},
@@ -41,7 +46,7 @@
4146
"abbrev": "^2.0.0",
4247
"bluebird": "^3.7.2",
4348
"command-exists": "^1.2.9",
44-
"hexo-fs": "^4.0.0",
49+
"hexo-fs": "^4.1.1",
4550
"hexo-log": "^3.0.0",
4651
"hexo-util": "^2.5.0",
4752
"minimist": "^1.2.5",
@@ -50,6 +55,10 @@
5055
"tildify": "^2.0.0"
5156
},
5257
"devDependencies": {
58+
"@types/bluebird": "^3.5.37",
59+
"@types/node": "^18.11.8",
60+
"@typescript-eslint/eslint-plugin": "^5.41.0",
61+
"@typescript-eslint/parser": "^5.41.0",
5362
"chai": "^4.3.4",
5463
"eslint": "^8.2.0",
5564
"eslint-config-hexo": "^5.0.0",
@@ -58,7 +67,9 @@
5867
"nyc": "^15.1.0",
5968
"proxyquire": "^2.1.3",
6069
"rewire": "^6.0.0",
61-
"sinon": "^14.0.0"
70+
"sinon": "^14.0.0",
71+
"ts-node": "^10.9.1",
72+
"typescript": "^4.8.4"
6273
},
6374
"engines": {
6475
"node": ">=14"

‎test/.eslintrc.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
{
2-
"extends": "hexo/test"
2+
"extends": "hexo/test",
3+
"rules": {
4+
"@typescript-eslint/no-var-requires": 0
5+
}
36
}

‎test/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
const chai = require('chai');
3+
require('chai');
44

55
describe('hexo-cli', () => {
66
require('./scripts/find_pkg');

‎test/scripts/context.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const should = require('chai').should();
55
const sinon = require('sinon');
66

77
describe('context', () => {
8-
const Context = require('../../lib/context');
8+
const Context = require('../../dist/context');
99

1010
describe('call', () => {
1111
const hexo = new Context();

‎test/scripts/find_pkg.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const { rmdir, writeFile, unlink } = require('hexo-fs');
55
const { dirname, join } = require('path');
66

77
describe('Find package', () => {
8-
const findPkg = require('../../lib/find_pkg');
8+
const findPkg = require('../../dist/find_pkg');
99
const baseDir = join(__dirname, 'find_pkg_test');
1010

1111
after(async () => await rmdir(baseDir));

‎test/scripts/help.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22

33
require('chai').should();
4-
const Context = require('../../lib/context');
4+
const Context = require('../../dist/context');
55
const sinon = require('sinon');
66
const { readFile } = require('hexo-fs');
77
const { join } = require('path');
@@ -13,10 +13,10 @@ function getConsoleLog({ args }) {
1313
}
1414

1515
describe('help', () => {
16-
const helpModule = rewire('../../lib/console/help');
16+
const helpModule = rewire('../../dist/console/help');
1717
const hexo = new Context();
1818

19-
require('../../lib/console')(hexo);
19+
require('../../dist/console')(hexo);
2020

2121
it('show global help', () => {
2222
const spy = sinon.spy();

‎test/scripts/hexo.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ describe('hexo', () => {
99

1010
it('run help if no specified command', async () => {
1111
const spy = sinon.spy();
12-
const hexo = proxyquire('../../lib/hexo', {
12+
const hexo = proxyquire('../../dist/hexo', {
1313
'./console'(ctx) {
1414
ctx.extend.console.register('help', spy);
1515
}
@@ -21,7 +21,7 @@ describe('hexo', () => {
2121

2222
it('run specified command', async () => {
2323
const spy = sinon.spy();
24-
const hexo = proxyquire('../../lib/hexo', {
24+
const hexo = proxyquire('../../dist/hexo', {
2525
'./console'(ctx) {
2626
ctx.extend.console.register('test', spy);
2727
}
@@ -33,7 +33,7 @@ describe('hexo', () => {
3333

3434
it('run help if specified command not found', async () => {
3535
const spy = sinon.spy();
36-
const hexo = proxyquire('../../lib/hexo', {
36+
const hexo = proxyquire('../../dist/hexo', {
3737
'./console'(ctx) {
3838
ctx.extend.console.register('help', spy);
3939
}

‎test/scripts/init.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ const { join } = require('path');
55
const { listDir, rmdir, createReadStream } = require('hexo-fs');
66
const { createSha1Hash } = require('hexo-util');
77
const rewire = require('rewire');
8-
const Context = require('../../lib/context');
8+
const Context = require('../../dist/context');
99
const assetDir = join(__dirname, '../../assets');
1010

1111
describe('init', () => {
1212
const baseDir = join(__dirname, 'init_test');
13-
const initModule = rewire('../../lib/console/init');
13+
const initModule = rewire('../../dist/console/init');
1414
const hexo = new Context(baseDir, { silent: true });
1515
const init = initModule.bind(hexo);
1616
let assets = [];
@@ -57,7 +57,7 @@ describe('init', () => {
5757
}
5858

5959
function withoutSpawn(fn) {
60-
return initModule.__with__('spawn', () => Promise.reject(new Error('spawn is not available')))(fn);
60+
return initModule.__with__('hexo_util_1.spawn', () => Promise.reject(new Error('spawn is not available')))(fn);
6161
}
6262

6363
before(async () => {

‎test/scripts/version.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22

33
require('chai').should();
4-
const Context = require('../../lib/context');
4+
const Context = require('../../dist/context');
55
const sinon = require('sinon');
66
const { platform, release } = require('os');
77
const { format } = require('util');
@@ -14,7 +14,7 @@ function getConsoleLog({ args }) {
1414
}
1515

1616
describe('version', () => {
17-
const versionModule = rewire('../../lib/console/version');
17+
const versionModule = rewire('../../dist/console/version');
1818
const hexo = new Context();
1919

2020
it('show version info', () => {

‎tsconfig.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"compilerOptions": {
3+
"module": "commonjs",
4+
"target": "es6",
5+
"sourceMap": true,
6+
"outDir": "dist",
7+
"declaration": true,
8+
"esModuleInterop": true,
9+
"types": [
10+
"node"
11+
]
12+
},
13+
"include": [
14+
"lib/hexo.ts"
15+
],
16+
"exclude": [
17+
"node_modules"
18+
]
19+
}

0 commit comments

Comments
 (0)
Please sign in to comment.