Skip to content

Commit 3e172c6

Browse files
committed
Add JSDoc based types
1 parent b06388e commit 3e172c6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+871
-177
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.DS_Store
2+
*.d.ts
23
*.log
34
coverage/
45
node_modules/

index.js

Lines changed: 103 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
1+
/**
2+
* @typedef {import('./lib/types.js').Node} Node
3+
* @typedef {import('./lib/types.js').Element} Element
4+
* @typedef {import('./lib/types.js').Text} Text
5+
* @typedef {import('./lib/types.js').Options} Options
6+
* @typedef {import('./lib/types.js').Context} Context
7+
* @typedef {import('./lib/types.js').Properties} Properties
8+
* @typedef {import('./lib/types.js').H} H
9+
* @typedef {import('./lib/types.js').HWithoutProps} HWithoutProps
10+
* @typedef {import('./lib/types.js').HWithProps} HWithProps
11+
* @typedef {import('./lib/types.js').MdastNode} MdastNode
12+
* @typedef {import('./lib/types.js').MdastRoot} MdastRoot
13+
*/
14+
115
import {hasProperty} from 'hast-util-has-property'
2-
import minify from 'rehype-minify-whitespace'
16+
import minifyWhitespace from 'rehype-minify-whitespace'
317
import {convert} from 'unist-util-is'
418
import {visit} from 'unist-util-visit'
519
import {one} from './lib/one.js'
@@ -8,70 +22,97 @@ import {own} from './lib/util/own.js'
822

923
var block = convert(['heading', 'paragraph', 'root'])
1024

11-
export function toMdast(tree, options) {
12-
var settings = options || {}
25+
/**
26+
* @param {Node} tree
27+
* @param {Options} [options]
28+
*/
29+
export function toMdast(tree, options = {}) {
30+
/** @type {Object.<string, Element>} */
1331
var byId = {}
32+
/** @type {MdastNode|Array.<MdastNode>|void} */
33+
var result
34+
/** @type {MdastNode|MdastRoot} */
1435
var mdast
1536

16-
h.nodeById = byId
17-
h.baseFound = false
18-
h.frozenBaseUrl = null
19-
h.wrapText = true
20-
h.qNesting = 0
21-
22-
h.handlers = settings.handlers
23-
? {...handlers, ...settings.handlers}
24-
: handlers
25-
h.augment = augment
26-
27-
h.document = settings.document
28-
h.checked = settings.checked || '[x]'
29-
h.unchecked = settings.unchecked || '[ ]'
30-
h.quotes = settings.quotes || ['"']
37+
/**
38+
* @type {H}
39+
*/
40+
var h = Object.assign(
41+
/**
42+
* @type {HWithProps & HWithoutProps}
43+
*/
44+
(
45+
/**
46+
* @param {Node} node
47+
* @param {string} type
48+
* @param {Properties|string|Array.<Node>} [props]
49+
* @param {string|Array.<Node>} [children]
50+
*/
51+
function (node, type, props, children) {
52+
/** @type {Node} */
53+
var result
54+
/** @type {Properties} */
55+
var properties
56+
57+
if (typeof props === 'string' || Array.isArray(props)) {
58+
children = props
59+
properties = {}
60+
} else {
61+
properties = props
62+
}
63+
64+
// @ts-ignore Assume valid `type` and `children`/`value`.
65+
result = {type, ...properties}
66+
67+
if (typeof children === 'string') {
68+
result.value = children
69+
} else if (children) {
70+
result.children = children
71+
}
72+
73+
if (node.position) {
74+
result.position = node.position
75+
}
76+
77+
return result
78+
}
79+
),
80+
{
81+
nodeById: byId,
82+
baseFound: false,
83+
wrapText: true,
84+
/** @type {string|null} */
85+
frozenBaseUrl: null,
86+
qNesting: 0,
87+
handlers: options.handlers
88+
? {...handlers, ...options.handlers}
89+
: handlers,
90+
document: options.document,
91+
checked: options.checked || '[x]',
92+
unchecked: options.unchecked || '[ ]',
93+
quotes: options.quotes || ['"']
94+
}
95+
)
3196

3297
visit(tree, 'element', onelement)
3398

34-
minify({newlines: settings.newlines === true})(tree)
35-
36-
mdast = one(h, tree, null)
37-
38-
visit(mdast, 'text', ontext)
39-
40-
return mdast
99+
minifyWhitespace({newlines: options.newlines === true})(tree)
41100

42-
function h(node, type, props, children) {
43-
var result
101+
result = one(h, tree, null)
44102

45-
if (
46-
!children &&
47-
(typeof props === 'string' ||
48-
(typeof props === 'object' && 'length' in props))
49-
) {
50-
children = props
51-
props = {}
52-
}
53-
54-
result = {type, ...props}
55-
56-
if (typeof children === 'string') {
57-
result.value = children
58-
} else if (children) {
59-
result.children = children
60-
}
61-
62-
return augment(node, result)
103+
if (!result) {
104+
mdast = {type: 'root', children: []}
105+
} else if (Array.isArray(result)) {
106+
mdast = {type: 'root', children: result}
107+
} else {
108+
mdast = result
63109
}
64110

65-
// To do: inline in a future major.
66-
// `right` is the finalized mdast node, created from `left`, a hast node.
67-
function augment(left, right) {
68-
if (left.position) {
69-
right.position = left.position
70-
}
111+
visit(mdast, 'text', ontext)
71112

72-
return right
73-
}
113+
return mdast
74114

115+
/** @type {import('unist-util-visit').Visitor<Element>} */
75116
function onelement(node) {
76117
var id = hasProperty(node, 'id') && String(node.properties.id).toUpperCase()
77118

@@ -80,11 +121,15 @@ export function toMdast(tree, options) {
80121
}
81122
}
82123

83-
// Collapse text nodes, and fix whitespace.
84-
// Most of this is taken care of by `rehype-minify-whitespace`, but
85-
// we’re generating some whitespace too, and some nodes are in the end
86-
// ignored.
87-
// So clean up:
124+
/**
125+
* Collapse text nodes, and fix whitespace.
126+
* Most of this is taken care of by `rehype-minify-whitespace`, but
127+
* we’re generating some whitespace too, and some nodes are in the end
128+
* ignored.
129+
* So clean up.
130+
*
131+
* @type {import('unist-util-visit').Visitor<Text>}
132+
*/
88133
function ontext(node, index, parent) {
89134
var previous = parent.children[index - 1]
90135

lib/all.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
1+
/**
2+
* @typedef {import('./types.js').H} H
3+
* @typedef {import('./types.js').Node} Node
4+
* @typedef {import('./types.js').Parent} Parent
5+
* @typedef {import('./types.js').Handle} Handle
6+
* @typedef {import('./types.js').MdastNode} MdastNode
7+
*/
8+
19
import {one} from './one.js'
210

11+
/**
12+
* @param {H} h
13+
* @param {Node} parent
14+
* @returns {Array.<MdastNode>}
15+
*/
316
export function all(h, parent) {
17+
/** @type {Array.<Node>} */
18+
// @ts-ignore Assume `parent` is a parent.
419
var nodes = parent.children || []
20+
/** @type {Array.<MdastNode>} */
521
var values = []
622
var index = -1
23+
/** @type {MdastNode|Array.<MdastNode>} */
724
var result
825

926
while (++index < nodes.length) {
27+
// @ts-ignore assume `parent` is a parent.
1028
result = one(h, nodes[index], parent)
1129

1230
if (result) {

lib/handlers/a.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1+
/**
2+
* @typedef {import('../types.js').Handle} Handle
3+
* @typedef {import('../types.js').Element} Element
4+
*/
5+
16
import {all} from '../all.js'
27
import {resolve} from '../util/resolve.js'
38

9+
/**
10+
* @type {Handle}
11+
* @param {Element} node
12+
*/
413
export function a(h, node) {
514
return h(
615
node,
716
'link',
817
{
918
title: node.properties.title || null,
10-
url: resolve(h, node.properties.href)
19+
url: resolve(h, String(node.properties.href || '') || null)
1120
},
1221
all(h, node)
1322
)

lib/handlers/base.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
/**
2+
* @typedef {import('../types.js').Handle} Handle
3+
* @typedef {import('../types.js').Element} Element
4+
*/
5+
6+
/**
7+
* @type {Handle}
8+
* @param {Element} node
9+
*/
110
export function base(h, node) {
211
if (!h.baseFound) {
3-
h.frozenBaseUrl = node.properties.href
12+
h.frozenBaseUrl = String(node.properties.href || '') || null
413
h.baseFound = true
514
}
615
}

lib/handlers/blockquote.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1+
/**
2+
* @typedef {import('../types.js').Handle} Handle
3+
* @typedef {import('../types.js').Element} Element
4+
*/
5+
16
import {wrapChildren} from '../util/wrap-children.js'
27

8+
/**
9+
* @type {Handle}
10+
* @param {Element} node
11+
*/
312
export function blockquote(h, node) {
413
return h(node, 'blockquote', wrapChildren(h, node))
514
}

lib/handlers/br.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
/**
2+
* @typedef {import('../types.js').Handle} Handle
3+
* @typedef {import('../types.js').Element} Element
4+
*/
5+
6+
/**
7+
* @type {Handle}
8+
* @param {Element} node
9+
*/
110
export function br(h, node) {
211
return h.wrapText ? h(node, 'break') : h(node, 'text', ' ')
312
}

lib/handlers/code.js

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
/**
2+
* @typedef {import('../types.js').Handle} Handle
3+
* @typedef {import('../types.js').Element} Element
4+
* @typedef {import('../types.js').ElementChild} ElementChild
5+
*/
6+
17
import {hasProperty} from 'hast-util-has-property'
28
import {convertElement} from 'hast-util-is-element'
39
import {toText} from 'hast-util-to-text'
@@ -6,33 +12,46 @@ import {wrapText} from '../util/wrap-text.js'
612

713
var prefix = 'language-'
814

15+
/** @type {import('unist-util-is').AssertPredicate<Element & {tagName: 'pre'}>} */
916
var pre = convertElement('pre')
17+
/** @type {import('unist-util-is').AssertPredicate<Element & {tagName: 'code'}>} */
1018
var isCode = convertElement('code')
1119

20+
/**
21+
* @type {Handle}
22+
* @param {Element} node
23+
*/
1224
export function code(h, node) {
1325
var children = node.children
1426
var index = -1
27+
/** @type {Array.<string|number>} */
1528
var classList
29+
/** @type {string} */
1630
var lang
31+
/** @type {ElementChild} */
32+
var child
1733

1834
if (pre(node)) {
1935
while (++index < children.length) {
36+
child = children[index]
37+
2038
if (
21-
isCode(children[index]) &&
22-
hasProperty(children[index], 'className')
39+
isCode(child) &&
40+
hasProperty(child, 'className') &&
41+
Array.isArray(child.properties.className)
2342
) {
24-
classList = children[index].properties.className
43+
classList = child.properties.className
2544
break
2645
}
2746
}
2847
}
2948

30-
if (classList) {
49+
if (Array.isArray(classList)) {
3150
index = -1
3251

3352
while (++index < classList.length) {
34-
if (classList[index].slice(0, prefix.length) === prefix) {
35-
lang = classList[index].slice(prefix.length)
53+
if (String(classList[index]).slice(0, prefix.length) === prefix) {
54+
lang = String(classList[index]).slice(prefix.length)
3655
break
3756
}
3857
}

lib/handlers/comment.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1+
/**
2+
* @typedef {import('../types.js').Handle} Handle
3+
* @typedef {import('../types.js').Comment} Comment
4+
*/
15
import {wrapText} from '../util/wrap-text.js'
26

7+
/**
8+
* @type {Handle}
9+
* @param {Comment} node
10+
*/
311
export function comment(h, node) {
412
return h(node, 'html', '<!--' + wrapText(h, node.value) + '-->')
513
}

lib/handlers/del.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1+
/**
2+
* @typedef {import('../types.js').Handle} Handle
3+
* @typedef {import('../types.js').Element} Element
4+
*/
5+
16
import {all} from '../all.js'
27

8+
/**
9+
* @type {Handle}
10+
* @param {Element} node
11+
*/
312
export function del(h, node) {
413
return h(node, 'delete', all(h, node))
514
}

0 commit comments

Comments
 (0)