Skip to content

Commit 7dbad66

Browse files
committed
Add JSDoc based types
1 parent 6a1a37c commit 7dbad66

File tree

9 files changed

+114
-77
lines changed

9 files changed

+114
-77
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
coverage/
22
node_modules/
33
.DS_Store
4+
*.d.ts
45
*.log
56
yarn.lock

index.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,44 @@
1+
/**
2+
* @typedef {import('mdast').Root} Root
3+
* @typedef {import('hast-util-sanitize').Schema} Schema
4+
* @typedef {import('mdast-util-to-hast').Handlers} Handlers
5+
*
6+
* @typedef Options
7+
* Configuration.
8+
* @property {boolean|Schema|null} [sanitize]
9+
* How to sanitize the output.
10+
* @property {Handlers} [handlers={}]
11+
* Object mapping mdast nodes to functions handling them.
12+
*/
13+
114
import {toHtml} from 'hast-util-to-html'
215
import {sanitize} from 'hast-util-sanitize'
316
import {toHast} from 'mdast-util-to-hast'
417

18+
/**
19+
* Plugin to serialize markdown as HTML.
20+
*
21+
* @type {import('unified').Plugin<[Options?]|void[], Root, string>}
22+
*/
523
export default function remarkHtml(options = {}) {
624
const handlers = options.handlers || {}
725
const schema =
826
options.sanitize && typeof options.sanitize === 'object'
927
? options.sanitize
10-
: null
28+
: undefined
1129

1230
Object.assign(this, {Compiler: compiler})
1331

32+
/**
33+
* @type {import('unified').CompilerFunction<Root, string>}
34+
*/
1435
function compiler(node, file) {
1536
const hast = toHast(node, {allowDangerousHtml: !options.sanitize, handlers})
37+
// @ts-expect-error: assume root.
38+
const cleanHast = options.sanitize ? sanitize(hast, schema) : hast
1639
const result = toHtml(
17-
options.sanitize ? sanitize(hast, schema) : hast,
40+
// @ts-expect-error: assume root.
41+
cleanHast,
1842
Object.assign({}, options, {allowDangerousHtml: !options.sanitize})
1943
)
2044

package.json

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,20 @@
3131
"sideEffects": false,
3232
"type": "module",
3333
"main": "index.js",
34+
"types": "index.d.ts",
3435
"files": [
36+
"index.d.ts",
3537
"index.js"
3638
],
3739
"dependencies": {
40+
"@types/mdast": "^3.0.0",
3841
"hast-util-sanitize": "^4.0.0",
3942
"hast-util-to-html": "^8.0.0",
40-
"mdast-util-to-hast": "^11.0.0"
43+
"mdast-util-to-hast": "^11.0.0",
44+
"unified": "^10.0.0"
4145
},
4246
"devDependencies": {
47+
"@types/tape": "^4.0.0",
4348
"c8": "^7.0.0",
4449
"commonmark.json": "^0.30.0",
4550
"is-hidden": "^2.0.0",
@@ -55,16 +60,19 @@
5560
"remark-preset-wooorm": "^8.0.0",
5661
"remark-slug": "^6.0.0",
5762
"remark-toc": "^7.0.0",
63+
"rimraf": "^3.0.0",
5864
"tape": "^5.0.0",
5965
"to-vfile": "^7.0.0",
60-
"unified": "^10.0.0",
66+
"type-coverage": "^2.0.0",
67+
"typescript": "^4.0.0",
6168
"xo": "^0.39.0"
6269
},
6370
"scripts": {
71+
"build": "rimraf \"test/**/*.d.ts\" \"*.d.ts\" && tsc && type-coverage",
6472
"format": "remark . -qfo --ignore-pattern test/ && prettier . -w --loglevel warn && xo --fix",
6573
"test-api": "node --conditions development test/index.js",
6674
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov npm run test-api",
67-
"test": "npm run format && npm run test-coverage"
75+
"test": "npm run build && npm run format && npm run test-coverage"
6876
},
6977
"prettier": {
7078
"tabWidth": 2,
@@ -75,14 +83,17 @@
7583
"trailingComma": "none"
7684
},
7785
"xo": {
78-
"prettier": true,
79-
"ignores": [
80-
"types/"
81-
]
86+
"prettier": true
8287
},
8388
"remarkConfig": {
8489
"plugins": [
8590
"preset-wooorm"
8691
]
92+
},
93+
"typeCoverage": {
94+
"atLeast": 100,
95+
"detail": true,
96+
"strict": true,
97+
"ignoreCatch": true
8798
}
8899
}

test/index.js

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
/**
2+
* @typedef {import('mdast').Root} Root
3+
* @typedef {import('mdast').Paragraph} Paragraph
4+
* @typedef {import('vfile').VFile} VFile
5+
* @typedef {import('../index.js').Options} Options
6+
*/
7+
18
import path from 'path'
29
import fs from 'fs'
310
import test from 'tape'
@@ -19,8 +26,6 @@ import rehypeStringify from 'rehype-stringify'
1926
import remarkHtml from '../index.js'
2027

2128
test('remarkHtml', (t) => {
22-
let processor
23-
2429
t.doesNotThrow(() => {
2530
remark().use(remarkHtml).freeze()
2631
}, 'should not throw if not passed options')
@@ -29,22 +34,25 @@ test('remarkHtml', (t) => {
2934
() => {
3035
remark()
3136
.use(remarkHtml)
37+
// @ts-expect-error: not a node.
3238
.stringify({type: 'root', children: [{value: 'baz'}]})
3339
},
3440
/Expected node, got `\[object Object]`/,
3541
'should throw when not given a node'
3642
)
3743

38-
processor = remark().use(remarkHtml)
44+
let processor = remark().use(remarkHtml)
3945

4046
t.equal(
47+
// @ts-expect-error: unknown node.
4148
processor.stringify({type: 'alpha'}),
4249
'<div></div>',
4350
'should stringify unknown nodes'
4451
)
4552

4653
t.equal(
4754
processor.stringify({
55+
// @ts-expect-error: unknown node.
4856
type: 'alpha',
4957
children: [{type: 'strong', children: [{type: 'text', value: 'bravo'}]}]
5058
}),
@@ -54,6 +62,7 @@ test('remarkHtml', (t) => {
5462

5563
t.equal(
5664
processor.stringify({
65+
// @ts-expect-error: unknown node.
5766
type: 'alpha',
5867
children: [{type: 'text', value: 'bravo'}],
5968
data: {
@@ -68,8 +77,14 @@ test('remarkHtml', (t) => {
6877

6978
processor = remark().use(remarkHtml, {
7079
handlers: {
80+
/** @param {Paragraph} node */
7181
paragraph(h, node) {
72-
node.children[0].value = 'changed'
82+
const head = node.children[0]
83+
84+
if (head.type === 'text') {
85+
head.value = 'changed'
86+
}
87+
7388
return h(node, 'p', all(h, node))
7489
}
7590
}
@@ -82,13 +97,15 @@ test('remarkHtml', (t) => {
8297
)
8398

8499
processor = remark()
85-
.use(() => {
86-
return function (ast) {
100+
.use(
101+
/** @type {import('unified').Plugin<void[], Root>} */
102+
() => (ast) => {
103+
// @ts-expect-error: assume it exists.
87104
ast.children[0].children[0].data = {
88105
hProperties: {title: 'overwrite'}
89106
}
90107
}
91-
})
108+
)
92109
.use(remarkHtml)
93110

94111
t.equal(
@@ -98,11 +115,13 @@ test('remarkHtml', (t) => {
98115
)
99116

100117
processor = remark()
101-
.use(() => {
102-
return function (ast) {
118+
.use(
119+
/** @type {import('unified').Plugin<void[], Root>} */
120+
() => (ast) => {
121+
// @ts-expect-error: assume it exists.
103122
ast.children[0].children[0].data = {hName: 'b'}
104123
}
105-
})
124+
)
106125
.use(remarkHtml)
107126

108127
t.equal(
@@ -112,8 +131,10 @@ test('remarkHtml', (t) => {
112131
)
113132

114133
processor = remark()
115-
.use(() => {
116-
return function (ast) {
134+
.use(
135+
/** @type {import('unified').Plugin<void[], Root>} */
136+
() => (ast) => {
137+
// @ts-expect-error: assume it exists.
117138
const code = ast.children[0].children[0]
118139

119140
code.data = {
@@ -127,7 +148,7 @@ test('remarkHtml', (t) => {
127148
]
128149
}
129150
}
130-
})
151+
)
131152
.use(remarkHtml)
132153

133154
t.equal(
@@ -137,8 +158,10 @@ test('remarkHtml', (t) => {
137158
)
138159

139160
processor = remark()
140-
.use(() => {
141-
return function (ast) {
161+
.use(
162+
/** @type {import('unified').Plugin<void[], Root>} */
163+
() => (ast) => {
164+
// @ts-expect-error: assume it exists.
142165
const code = ast.children[0].children[0]
143166

144167
code.data = {
@@ -152,7 +175,7 @@ test('remarkHtml', (t) => {
152175
]
153176
}
154177
}
155-
})
178+
)
156179
.use(remarkHtml, {sanitize: true})
157180

158181
t.equal(
@@ -162,13 +185,14 @@ test('remarkHtml', (t) => {
162185
)
163186

164187
processor = remark()
165-
.use(() => {
166-
return function (ast) {
188+
.use(
189+
/** @type {import('unified').Plugin<void[], Root>} */
190+
() => (ast) => {
167191
ast.children[0].data = {
168192
hProperties: {className: 'foo'}
169193
}
170194
}
171-
})
195+
)
172196
.use(remarkHtml)
173197

174198
t.equal(
@@ -242,7 +266,9 @@ test('Fixtures', (t) => {
242266
let config = {}
243267

244268
try {
245-
config = JSON.parse(fs.readFileSync(path.join(base, name, 'config.json')))
269+
config = JSON.parse(
270+
String(fs.readFileSync(path.join(base, name, 'config.json')))
271+
)
246272
} catch {}
247273

248274
const result = processSync(file, config)
@@ -256,6 +282,7 @@ test('Fixtures', (t) => {
256282
test('CommonMark', (t) => {
257283
let start = 0
258284
let index = -1
285+
/** @type {string|undefined} */
259286
let section
260287

261288
while (++index < commonmark.length) {
@@ -296,7 +323,7 @@ test('Integrations', (t) => {
296323
toc: [remarkSlug, remarkToc]
297324
}
298325
const base = path.join('test', 'integrations')
299-
const files = fs.readdirSync(base)
326+
const files = /** @type {(keyof integrationMap)[]} */ (fs.readdirSync(base))
300327
let index = -1
301328

302329
while (++index < files.length) {
@@ -308,6 +335,7 @@ test('Integrations', (t) => {
308335
const input = String(fs.readFileSync(path.join(base, name, 'input.md')))
309336
const file = toVFile({path: name + '.md', value: input})
310337
const result = remark()
338+
// @ts-expect-error: fine.
311339
.use(integrationMap[name])
312340
.use(remarkHtml)
313341
.processSync(file)
@@ -319,6 +347,10 @@ test('Integrations', (t) => {
319347
t.end()
320348
})
321349

350+
/**
351+
* @param {VFile} file
352+
* @param {Options} [config]
353+
*/
322354
function processSync(file, config) {
323355
return remark().use(remarkHtml, config).processSync(file).toString()
324356
}

tsconfig.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"include": ["test/**/*.js", "*.js"],
3+
"compilerOptions": {
4+
"target": "ES2020",
5+
"lib": ["ES2020"],
6+
"module": "ES2020",
7+
"moduleResolution": "node",
8+
"allowJs": true,
9+
"checkJs": true,
10+
"declaration": true,
11+
"emitDeclarationOnly": true,
12+
"allowSyntheticDefaultImports": true,
13+
"skipLibCheck": true,
14+
"strict": true
15+
}
16+
}

types/index.d.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.

types/remark-html-tests.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

types/tsconfig.json

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)