diff --git a/.mocharc.yml b/.mocharc.yml index b846d5d7..f93fd01e 100644 --- a/.mocharc.yml +++ b/.mocharc.yml @@ -1,3 +1,3 @@ reporter: spec opts: false -spec: "test/*.spec.js" +spec: "test/*.spec.ts" diff --git a/lib/camel_case_keys.ts b/lib/camel_case_keys.ts index 8a3a2c60..5f91d04f 100644 --- a/lib/camel_case_keys.ts +++ b/lib/camel_case_keys.ts @@ -27,7 +27,7 @@ function camelCaseKeys(obj: object) { if (typeof obj !== 'object') throw new TypeError('obj must be an object!'); const keys = Object.keys(obj); - const result = {}; + const result: Record = {}; for (const oldKey of keys) { const newKey = toCamelCase(oldKey); diff --git a/lib/full_url_for.ts b/lib/full_url_for.ts index 4fa63cbb..cb55c53b 100644 --- a/lib/full_url_for.ts +++ b/lib/full_url_for.ts @@ -2,7 +2,7 @@ import { parse } from 'url'; import encodeURL from './encode_url'; import prettyUrls from './pretty_urls'; import Cache from './cache'; -const cache = new Cache(); +const cache = new Cache(); function fullUrlForHelper(path = '/') { const { config } = this; diff --git a/lib/html_tag.ts b/lib/html_tag.ts index 388457aa..6660dfdc 100644 --- a/lib/html_tag.ts +++ b/lib/html_tag.ts @@ -14,8 +14,8 @@ function encSrcset(str: string) { return str; } -function htmlTag(tag: string, attrs: { - [key: string]: string | boolean | null | undefined; +function htmlTag(tag: string, attrs?: { + [key: string]: string | boolean | number | null | undefined; }, text?: string, escape = true) { if (!tag) throw new TypeError('tag is required!'); diff --git a/lib/toc_obj.ts b/lib/toc_obj.ts index e24aef9c..7c6d8c08 100644 --- a/lib/toc_obj.ts +++ b/lib/toc_obj.ts @@ -40,7 +40,7 @@ function tocObj(str: string, options = {}) { if (!headingsLen) return []; - const result = []; + const result: Result[] = []; for (let i = 0; i < headingsLen; i++) { const el = headings[i]; diff --git a/lib/truncate.ts b/lib/truncate.ts index 2218f3cd..cbbb52e3 100644 --- a/lib/truncate.ts +++ b/lib/truncate.ts @@ -4,7 +4,7 @@ interface Options { separator?: string; } -function truncate(str: string, options: Options = {}) { +function truncate(str: string, options: Options = {}): string { if (typeof str !== 'string') throw new TypeError('str must be a string!'); const length = options.length || 30; diff --git a/package.json b/package.json index 918a9a0e..ddd576ef 100644 --- a/package.json +++ b/package.json @@ -34,12 +34,14 @@ ], "license": "MIT", "devDependencies": { + "@types/chai": "^4.3.11", "@types/cross-spawn": "^6.0.2", + "@types/mocha": "^10.0.6", "@types/node": "^18.11.8", "@types/prismjs": "^1.26.0", + "@types/rewire": "^2.5.30", "c8": "^9.1.0", "chai": "^4.3.6", - "chai-as-promised": "^7.1.1", "domhandler": "^5.0.3", "eslint": "^8.23.0", "eslint-config-hexo": "^5.0.0", diff --git a/test/.eslintrc.json b/test/.eslintrc.json index 26f258b3..658b30cf 100644 --- a/test/.eslintrc.json +++ b/test/.eslintrc.json @@ -1,7 +1,13 @@ { - "extends": "hexo/test", + "extends": "hexo/ts-test", "rules": { + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/ban-ts-comment": 0, + "@typescript-eslint/no-non-null-assertion": 0, + "node/no-unsupported-features/es-syntax": 0, "@typescript-eslint/no-var-requires": 0, - "@typescript-eslint/no-empty-function": 0 + "@typescript-eslint/no-empty-function": 0, + "@typescript-eslint/no-unused-vars": 0, + "node/no-missing-require": 0 } } \ No newline at end of file diff --git a/test/cache.spec.js b/test/cache.spec.ts similarity index 88% rename from test/cache.spec.js rename to test/cache.spec.ts index 2864825a..716006b3 100644 --- a/test/cache.spec.js +++ b/test/cache.spec.ts @@ -1,14 +1,13 @@ -'use strict'; - -require('chai').should(); +import chai from 'chai'; +import Cache from '../lib/cache'; +chai.should(); describe('Cache', () => { - const Cache = require('../dist/cache'); - const cache = new Cache(); + const cache = new Cache(); it('get & set', () => { cache.set('foo', 123); - cache.get('foo').should.eql(123); + cache.get('foo')!.should.eql(123); }); it('size', () => { diff --git a/test/cache_stream.spec.js b/test/cache_stream.spec.ts similarity index 71% rename from test/cache_stream.spec.js rename to test/cache_stream.spec.ts index 76e7d9a0..55825549 100644 --- a/test/cache_stream.spec.js +++ b/test/cache_stream.spec.ts @@ -1,12 +1,10 @@ -'use strict'; +import chai from 'chai'; +import { Readable } from 'stream'; +import CacheStream from '../lib/cache_stream'; -require('chai').should(); - -const { Readable } = require('stream'); +chai.should(); describe('CacheStream', () => { - const CacheStream = require('../dist/cache_stream'); - it('default', () => { const src = new Readable(); const cacheStream = new CacheStream(); diff --git a/test/camel_case_keys.spec.js b/test/camel_case_keys.spec.ts similarity index 89% rename from test/camel_case_keys.spec.js rename to test/camel_case_keys.spec.ts index 63bff12a..2971a3d8 100644 --- a/test/camel_case_keys.spec.js +++ b/test/camel_case_keys.spec.ts @@ -1,10 +1,8 @@ -'use strict'; - -require('chai').should(); +import chai from 'chai'; +import camelCaseKeys from '../lib/camel_case_keys'; +chai.should(); describe('camelCaseKeys', () => { - const camelCaseKeys = require('../dist/camel_case_keys'); - it('default', () => { const result = camelCaseKeys({ foo_bar: 'test' diff --git a/test/color.spec.js b/test/color.spec.ts similarity index 96% rename from test/color.spec.js rename to test/color.spec.ts index 093c385c..a7359195 100644 --- a/test/color.spec.js +++ b/test/color.spec.ts @@ -1,10 +1,8 @@ -'use strict'; - -require('chai').should(); +import chai from 'chai'; +import Color from '../lib/color'; +chai.should(); describe('color', () => { - const Color = require('../dist/color'); - it('name', () => { const red = new Color('red'); const pink = new Color('pink'); @@ -67,6 +65,7 @@ describe('color', () => { it('invalid color', () => { let color; try { + // @ts-ignore color = new Color(200); } catch (e) { e.message.should.eql('color is required!'); diff --git a/test/decode_url.spec.js b/test/decode_url.spec.ts similarity index 96% rename from test/decode_url.spec.js rename to test/decode_url.spec.ts index d6bc3c3e..95945475 100644 --- a/test/decode_url.spec.js +++ b/test/decode_url.spec.ts @@ -1,10 +1,8 @@ -'use strict'; - -require('chai').should(); +import chai from 'chai'; +import decodeURL from '../lib/decode_url'; +chai.should(); describe('decodeURL', () => { - const decodeURL = require('../dist/decode_url'); - it('regular', () => { const content = 'http://foo.com/'; decodeURL(content).should.eql(content); diff --git a/test/deep_merge.spec.js b/test/deep_merge.spec.ts similarity index 59% rename from test/deep_merge.spec.js rename to test/deep_merge.spec.ts index a9b996d8..27f696e4 100644 --- a/test/deep_merge.spec.js +++ b/test/deep_merge.spec.ts @@ -1,36 +1,34 @@ -'use strict'; - -require('chai').should(); +import chai from 'chai'; +import deepMerge from '../lib/deep_merge'; +chai.should(); // The test is modified based on https://github.com/jonschlinkert/merge-deep/blob/master/test.js describe('deepMerge()', () => { - const deepMerge = require('../dist/deep_merge'); - it('should act as lodash.merge', () => { - const obj1 = { 'a': [{ 'b': 2 }, { 'd': 4 }] }; - const obj2 = { 'a': [{ 'c': 3 }, { 'e': 5 }] }; + const obj1: any = { 'a': [{ 'b': 2 }, { 'd': 4 }] }; + const obj2: any = { 'a': [{ 'c': 3 }, { 'e': 5 }] }; const expected = { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }; - - deepMerge(obj1, obj2).should.eql(expected); + const result: any = deepMerge(obj1, obj2); + result.should.eql(expected); }); it('should do a deep merge', () => { - const obj1 = {a: {b: 1, c: 1, d: {e: 1, f: 1}}}; - const obj2 = {a: {b: 2, d: {f: 'f'} }}; + const obj1: any = {a: {b: 1, c: 1, d: {e: 1, f: 1}}}; + const obj2: any = {a: {b: 2, d: {f: 'f'} }}; const expected = {a: {b: 2, c: 1, d: {e: 1, f: 'f'} }}; - - deepMerge(obj1, obj2).should.eql(expected); + const result: any = deepMerge(obj1, obj2); + result.should.eql(expected); }); it('should not merge strings', () => { - const obj1 = {a: 'fooo'}; - const obj2 = {a: {b: 2, d: {f: 'f'} }}; - const obj3 = {a: 'bar'}; + const obj1: any = {a: 'fooo'}; + const obj2: any = {a: {b: 2, d: {f: 'f'} }}; + const obj3: any = {a: 'bar'}; - const result = deepMerge(deepMerge(obj1, obj2), obj3); + const result: any = deepMerge(deepMerge(obj1, obj2), obj3); result.a.should.eql('bar'); }); @@ -45,10 +43,11 @@ describe('deepMerge()', () => { }); it('should not merge an objects into an array', () => { - const obj1 = {a: {b: 1}}; - const obj2 = {a: ['foo', 'bar']}; + const obj1: any = {a: {b: 1}}; + const obj2: any = {a: ['foo', 'bar']}; - deepMerge(obj1, obj2).should.eql({a: ['foo', 'bar']}); + const result: any = deepMerge(obj1, obj2); + result.should.eql({a: ['foo', 'bar']}); }); it('should not affect target & source', () => { @@ -68,10 +67,10 @@ describe('deepMerge()', () => { }); it('should deep clone arrays during merge', () => { - const obj1 = {a: [1, 2, [3, 4]]}; - const obj2 = {b: [5, 6]}; + const obj1: any = {a: [1, 2, [3, 4]]}; + const obj2: any = {b: [5, 6]}; - const result = deepMerge(obj1, obj2); + const result: any = deepMerge(obj1, obj2); result.a.should.eql([1, 2, [3, 4]]); result.a[2].should.eql([3, 4]); diff --git a/test/encode_url.spec.js b/test/encode_url.spec.ts similarity index 96% rename from test/encode_url.spec.js rename to test/encode_url.spec.ts index a8b70b6c..583df516 100644 --- a/test/encode_url.spec.js +++ b/test/encode_url.spec.ts @@ -1,10 +1,8 @@ -'use strict'; - -require('chai').should(); +import chai from 'chai'; +import encodeURL from '../lib/encode_url'; +chai.should(); describe('encodeURL', () => { - const encodeURL = require('../dist/encode_url'); - it('regular', () => { const content = 'http://foo.com/'; encodeURL(content).should.eql(content); diff --git a/test/escape_diacritic.spec.js b/test/escape_diacritic.spec.ts similarity index 70% rename from test/escape_diacritic.spec.js rename to test/escape_diacritic.spec.ts index eaf55073..6f8441c1 100644 --- a/test/escape_diacritic.spec.js +++ b/test/escape_diacritic.spec.ts @@ -1,10 +1,8 @@ -'use strict'; - -require('chai').should(); +import chai from 'chai'; +import escapeDiacritic from '../lib/escape_diacritic'; +chai.should(); describe('escapeDiacritic', () => { - const escapeDiacritic = require('../dist/escape_diacritic'); - it('default', () => { escapeDiacritic('Hell\u00F2 w\u00F2rld').should.eql('Hello world'); }); diff --git a/test/escape_html.spec.js b/test/escape_html.spec.ts similarity index 86% rename from test/escape_html.spec.js rename to test/escape_html.spec.ts index cf2835cc..5f4528f5 100644 --- a/test/escape_html.spec.js +++ b/test/escape_html.spec.ts @@ -1,10 +1,8 @@ -'use strict'; - -require('chai').should(); +import chai from 'chai'; +import escapeHTML from '../lib/escape_html'; +chai.should(); describe('escapeHTML', () => { - const escapeHTML = require('../dist/escape_html'); - it('default', () => { escapeHTML('

Hello "world".

').should.eql('<p class="foo">Hello "world".</p>'); }); diff --git a/test/escape_regexp.spec.js b/test/escape_regexp.spec.ts similarity index 69% rename from test/escape_regexp.spec.js rename to test/escape_regexp.spec.ts index b0fe15ff..9ffd44d1 100644 --- a/test/escape_regexp.spec.js +++ b/test/escape_regexp.spec.ts @@ -1,10 +1,8 @@ -'use strict'; - -require('chai').should(); +import chai from 'chai'; +import escapeRegExp from '../lib/escape_regexp'; +chai.should(); describe('escapeRegExp', () => { - const escapeRegExp = require('../dist/escape_regexp'); - it('default', () => { escapeRegExp('hello*world').should.eql('hello\\*world'); }); diff --git a/test/full_url_for.spec.js b/test/full_url_for.spec.ts old mode 100755 new mode 100644 similarity index 93% rename from test/full_url_for.spec.js rename to test/full_url_for.spec.ts index 39afa7ac..b7b1f0d8 --- a/test/full_url_for.spec.js +++ b/test/full_url_for.spec.ts @@ -1,13 +1,15 @@ -'use strict'; +import chai from 'chai'; +import fullUrlForHelper from '../lib/full_url_for'; +chai.should(); describe('full_url_for', () => { - const ctx = { + const ctx: any = { config: { url: 'http://example.com' } }; - const fullUrlFor = require('../dist/full_url_for').bind(ctx); + const fullUrlFor: typeof fullUrlForHelper = fullUrlForHelper.bind(ctx); it('internal url - root directory', () => { ctx.config.url = 'https://example.com'; diff --git a/test/gravatar.spec.js b/test/gravatar.spec.ts similarity index 84% rename from test/gravatar.spec.js rename to test/gravatar.spec.ts index b350ce2c..99ce5cb3 100644 --- a/test/gravatar.spec.js +++ b/test/gravatar.spec.ts @@ -1,10 +1,7 @@ -'use strict'; - -const { createHash } = require('crypto'); +import { createHash } from 'crypto'; +import gravatar from '../lib/gravatar'; describe('gravatar', () => { - const gravatar = require('../dist/gravatar'); - function md5(str) { return createHash('md5').update(str).digest('hex'); } diff --git a/test/hash.spec.js b/test/hash.spec.ts similarity index 67% rename from test/hash.spec.js rename to test/hash.spec.ts index f1b50983..f4b0b6ce 100644 --- a/test/hash.spec.js +++ b/test/hash.spec.ts @@ -1,25 +1,21 @@ -'use strict'; - -require('chai').should(); -const crypto = require('crypto'); +import { createHash } from 'crypto'; +import { hash, createSha1Hash } from '../lib/hash'; function sha1(content) { - const hash = crypto.createHash('sha1'); + const hash = createHash('sha1'); hash.update(content); return hash.digest(); } describe('hash', () => { - const hash = require('../dist/hash'); - it('hash', () => { const content = '123456'; - hash.hash(content).should.eql(sha1(content)); + hash(content).should.eql(sha1(content)); }); it('createSha1Hash', () => { - const _sha1 = hash.createSha1Hash(); + const _sha1 = createSha1Hash(); const content = '123456'; _sha1.update(content); _sha1.digest().should.eql(sha1(content)); @@ -28,7 +24,7 @@ describe('hash', () => { it('createSha1Hash - streamMode', () => { const content1 = '123456'; const content2 = '654321'; - const stream = hash.createSha1Hash(); + const stream = createSha1Hash(); // explicit convert stream.write(Buffer.from(content1)); // implicit convert diff --git a/test/highlight.spec.js b/test/highlight.spec.ts similarity index 96% rename from test/highlight.spec.js rename to test/highlight.spec.ts index 0dec8a04..0d4ddf00 100644 --- a/test/highlight.spec.js +++ b/test/highlight.spec.ts @@ -1,8 +1,9 @@ -'use strict'; +import chai from 'chai'; +import hljs from 'highlight.js'; +import { encode } from 'html-entities'; +import highlight from '../lib/highlight'; -const should = require('chai').should(); // eslint-disable-line -const hljs = require('highlight.js'); -const entities = require('html-entities'); +const should = chai.should(); // eslint-disable-line const validator = require('html-tag-validator'); const testJson = { @@ -33,7 +34,7 @@ function gutter(start, end) { return result; } -function code(str, lang) { +function code(str, lang?) { let data; if (lang) { @@ -43,7 +44,7 @@ function code(str, lang) { } else if (lang === null) { data = {value: str}; } else { - data = {value: entities.encode(str)}; + data = {value: encode(str)}; } const lines = data.value.split('\n'); @@ -68,8 +69,6 @@ function validateHtmlAsync(str, done) { } describe('highlight', () => { - const highlight = require('../dist/highlight'); - it('default', done => { const result = highlight(testString); assertResult(result, gutter(1, 4), code(testString)); @@ -96,7 +95,7 @@ describe('highlight', () => { const result = highlight(testString, {gutter: false, wrap: false}); result.should.eql([ '
',
-      entities.encode(testString),
+      encode(testString),
       '
' ].join('')); validateHtmlAsync(result, done); @@ -106,7 +105,7 @@ describe('highlight', () => { const result = highlight(testString, {gutter: false, wrap: false, hljs: true}); result.should.eql([ '
',
-      entities.encode(testString),
+      encode(testString),
       '
' ].join('')); validateHtmlAsync(result, done); @@ -139,7 +138,7 @@ describe('highlight', () => { }); it('wrap: false (with mark)', done => { - const result = highlight(testString, {gutter: false, wrap: false, hljs: true, lang: 'json', mark: '1'}); + const result = highlight(testString, {gutter: false, wrap: false, hljs: true, lang: 'json', mark: [1]}); hljs.configure({classPrefix: 'hljs-'}); result.should.eql([ '
',
@@ -229,7 +228,7 @@ describe('highlight', () => {
       '
',
       `
${caption}
`, '', - entities.encode(testString), + encode(testString), '
' ].join('')); validateHtmlAsync(result, done); @@ -453,7 +452,7 @@ describe('highlight', () => { console.log(result); result.should.eql([ '
',
-      entities.encode(testString),
+      encode(testString),
       '
' ].join('')); validateHtmlAsync(result, done); diff --git a/test/html_tag.spec.js b/test/html_tag.spec.ts similarity index 96% rename from test/html_tag.spec.js rename to test/html_tag.spec.ts index ef414a10..5649dbd8 100644 --- a/test/html_tag.spec.js +++ b/test/html_tag.spec.ts @@ -1,11 +1,9 @@ -'use strict'; - -require('chai').should(); +import chai from 'chai'; +import htmlTag from '../lib/html_tag'; +import encodeURL from '../lib/encode_url'; +chai.should(); describe('htmlTag', () => { - const htmlTag = require('../dist/html_tag'); - const encodeURL = require('../dist/encode_url'); - it('tag', () => { htmlTag('hr').should.eql('
'); }); @@ -58,6 +56,7 @@ describe('htmlTag', () => { it('tag is required', () => { try { + // @ts-ignore htmlTag(); } catch (err) { err.should.have.property('message', 'tag is required!'); diff --git a/test/is_external_link.spec.js b/test/is_external_link.spec.ts similarity index 96% rename from test/is_external_link.spec.js rename to test/is_external_link.spec.ts index 2b06821a..b9ca0843 100644 --- a/test/is_external_link.spec.js +++ b/test/is_external_link.spec.ts @@ -1,14 +1,12 @@ -'use strict'; +import isExternalLink from '../lib/is_external_link'; describe('isExternalLink', () => { - const ctx = { + const ctx: any = { config: { url: 'https://example.com' } }; - const isExternalLink = require('../dist/is_external_link'); - it('invalid url', () => { isExternalLink('https://localhost:4000你好', ctx.config.url).should.eql(false); }); diff --git a/test/pattern.spec.js b/test/pattern.spec.ts similarity index 94% rename from test/pattern.spec.js rename to test/pattern.spec.ts index 75fa3d5a..6c779830 100644 --- a/test/pattern.spec.js +++ b/test/pattern.spec.ts @@ -1,10 +1,8 @@ -'use strict'; - -require('chai').should(); +import chai from 'chai'; +import Pattern from '../lib/pattern'; +chai.should(); describe('Pattern', () => { - const Pattern = require('../dist/pattern'); - it('String - posts/:id', () => { const pattern = new Pattern('posts/:id'); const result = pattern.match('/posts/89'); @@ -66,6 +64,7 @@ describe('Pattern', () => { it('rule is required', () => { (() => { + // @ts-ignore // eslint-disable-next-line no-new new Pattern(); }).should.throw('rule must be a function, a string or a regular expression.'); diff --git a/test/permalink.spec.js b/test/permalink.spec.ts similarity index 96% rename from test/permalink.spec.js rename to test/permalink.spec.ts index 4eb47b42..a73ddb8f 100644 --- a/test/permalink.spec.js +++ b/test/permalink.spec.ts @@ -1,9 +1,8 @@ -'use strict'; - -require('chai').should(); +import chai from 'chai'; +import Permalink from '../lib/permalink'; +chai.should(); describe('Permalink', () => { - const Permalink = require('../dist/permalink'); let permalink; it('constructor', () => { @@ -46,6 +45,7 @@ describe('Permalink', () => { it('rule is required', () => { try { + // @ts-ignore // eslint-disable-next-line no-new new Permalink(); } catch (err) { diff --git a/test/pretty_utls.spec.js b/test/pretty_utls.spec.ts similarity index 93% rename from test/pretty_utls.spec.js rename to test/pretty_utls.spec.ts index d56ec6a4..01b259e8 100644 --- a/test/pretty_utls.spec.js +++ b/test/pretty_utls.spec.ts @@ -1,10 +1,8 @@ -'use strict'; - -require('chai').should(); +import chai from 'chai'; +import prettyUrls from '../lib/pretty_urls'; +chai.should(); describe('prettyUrls', () => { - const prettyUrls = require('../dist/pretty_urls'); - it('default', () => { prettyUrls('//example.com/index.html').should.eql('//example.com/index.html'); prettyUrls('/bar/foo.html').should.eql('/bar/foo.html'); diff --git a/test/prism.spec.js b/test/prism.spec.ts similarity index 98% rename from test/prism.spec.js rename to test/prism.spec.ts index a76a777d..d98ed197 100644 --- a/test/prism.spec.js +++ b/test/prism.spec.ts @@ -1,9 +1,9 @@ -'use strict'; - -require('chai').should(); -const escapeHTML = require('../dist/escape_html'); -const stripIndent = require('strip-indent'); +import chai from 'chai'; +import escapeHTML from '../lib/escape_html'; +import prismHighlight from '../lib/prism'; +import stripIndent from 'strip-indent'; +chai.should(); const validator = require('html-tag-validator'); function validateHtmlAsync(str, done) { validator(str, { @@ -27,8 +27,6 @@ const lineNumberStartTag = '