Skip to content

Commit ab521c3

Browse files
committed
Add JSDoc based types
1 parent 9eb35fa commit ab521c3

28 files changed

+282
-173
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.DS_Store
2+
*.d.ts
23
*.log
3-
.nyc_output/
44
coverage/
55
node_modules/
66
yarn.lock

.prettierignore

-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
coverage/
2-
*.json
32
*.md

index.js

+4
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1+
/**
2+
* @typedef {import('./lib/index.js').Options} Options
3+
*/
4+
15
export {toXml} from './lib/index.js'

lib/all.js

+18-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,28 @@
1+
/**
2+
* @typedef {import('./index.js').Parent} Parent
3+
* @typedef {import('./index.js').Context} Context
4+
* @typedef {import('./index.js').Child} Child
5+
*/
6+
17
import {one} from './one.js'
28

3-
// Serialize all children of `parent`.
4-
export function all(parent, config) {
9+
/**
10+
* Serialize all children of `parent`.
11+
*
12+
* @param {Parent} parent
13+
* @param {Context} ctx
14+
* @returns {string}
15+
*
16+
*/
17+
export function all(parent, ctx) {
18+
/** @type {Array.<Child>} */
519
var children = (parent && parent.children) || []
620
var index = -1
21+
/** @type {Array.<string>} */
722
var results = []
823

924
while (++index < children.length) {
10-
results[index] = one(children[index], config)
25+
results[index] = one(children[index], ctx)
1126
}
1227

1328
return results.join('')

lib/cdata.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
1+
/**
2+
* @typedef {import('./index.js').Handle} Handle
3+
* @typedef {import('./index.js').Cdata} Cdata
4+
*/
5+
16
import {escape} from './util-escape.js'
27

38
var unsafe = /]]>/g
49
var subset = ['>']
510

6-
// Serialize a CDATA section.
11+
/**
12+
* Serialize a CDATA section.
13+
*
14+
* @type {Handle}
15+
* @param {Cdata} node
16+
*/
717
export function cdata(node) {
818
return '<![CDATA[' + escape(node.value, subset, unsafe) + ']]>'
919
}

lib/comment.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1+
/**
2+
* @typedef {import('./index.js').Handle} Handle
3+
* @typedef {import('./index.js').Comment} Comment
4+
*/
5+
16
import {escape} from './util-escape.js'
27

3-
// Serialize a comment.
8+
/**
9+
* Serialize a comment.
10+
*
11+
* @type {Handle}
12+
* @param {Comment} node
13+
*/
414
export function comment(node) {
515
return '<!--' + escape(node.value, ['-']) + '-->'
616
}

lib/doctype.js

+14-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
1+
/**
2+
* @typedef {import('./index.js').Handle} Handle
3+
* @typedef {import('./index.js').Doctype} Doctype
4+
*/
5+
16
import {name} from './name.js'
27
import {value} from './value.js'
38

4-
// Serialize a document type.
5-
export function doctype(node, config) {
9+
/**
10+
* Serialize a doctype.
11+
*
12+
* @type {Handle}
13+
* @param {Doctype} node
14+
*/
15+
export function doctype(node, ctx) {
616
var nodeName = name(node.name)
717
var pub = node.public
818
var sys = node.system
@@ -13,13 +23,13 @@ export function doctype(node, config) {
1323
}
1424

1525
if (pub !== null && pub !== undefined && pub !== '') {
16-
result += ' PUBLIC ' + value(pub, config)
26+
result += ' PUBLIC ' + value(pub, ctx)
1727
} else if (sys !== null && sys !== undefined && sys !== '') {
1828
result += ' SYSTEM'
1929
}
2030

2131
if (sys !== null && sys !== undefined && sys !== '') {
22-
result += ' ' + value(sys, config)
32+
result += ' ' + value(sys, ctx)
2333
}
2434

2535
return result + '>'

lib/element.js

+21-6
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,40 @@
1+
/**
2+
* @typedef {import('./index.js').Handle} Handle
3+
* @typedef {import('./index.js').Element} Element
4+
* @typedef {import('./index.js').Attributes} Attributes
5+
*/
6+
17
import {all} from './all.js'
28
import {name} from './name.js'
39
import {value} from './value.js'
410

511
var own = {}.hasOwnProperty
612

7-
// Serialize an element.
8-
export function element(node, config) {
13+
/**
14+
* Serialize an element.
15+
*
16+
* @type {Handle}
17+
* @param {Element} node
18+
*/
19+
export function element(node, ctx) {
920
var nodeName = name(node.name)
10-
var content = all(node, config)
21+
var content = all(node, ctx)
22+
/** @type {Attributes} */
1123
var attributes = node.attributes || {}
12-
var close = content ? false : config.close
24+
var close = content ? false : ctx.close
25+
/** @type {Array.<string>} */
1326
var attrs = []
27+
/** @type {string} */
1428
var key
29+
/** @type {Attributes[keyof Attributes]} */
1530
var result
1631

1732
for (key in attributes) {
1833
if (own.call(attributes, key)) {
1934
result = attributes[key]
2035

2136
if (result !== null && result !== undefined) {
22-
attrs.push(name(key) + '=' + value(result, config))
37+
attrs.push(name(key) + '=' + value(result, ctx))
2338
}
2439
}
2540
}
@@ -28,7 +43,7 @@ export function element(node, config) {
2843
'<' +
2944
nodeName +
3045
(attrs.length === 0 ? '' : ' ' + attrs.join(' ')) +
31-
(close ? (config.tight ? '' : ' ') + '/' : '') +
46+
(close ? (ctx.tight ? '' : ' ') + '/' : '') +
3247
'>' +
3348
content +
3449
(close ? '' : '</' + nodeName + '>')

lib/index.js

+63-26
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,72 @@
1-
import {one} from './one.js'
1+
/**
2+
* @typedef {import('xast').Root} Root
3+
* @typedef {import('xast').Element} Element
4+
* @typedef {import('xast').Cdata} Cdata
5+
* @typedef {import('xast').Comment} Comment
6+
* @typedef {import('xast').Doctype} Doctype
7+
* @typedef {import('xast').Instruction} Instruction
8+
* @typedef {import('xast').Text} Text
9+
* @typedef {import('xast').Literal & {type: 'raw'}} Raw
10+
* @typedef {Root|Element} Parent
11+
* @typedef {import('xast').Attributes} Attributes
12+
* @typedef {Root['children'][number]} Child
13+
* @typedef {Child|Root} Node
14+
*
15+
* @typedef {'"'|"'"} Quote
16+
*
17+
* @typedef Options
18+
* @property {Quote} [quote='"'] Preferred quote to use
19+
* @property {boolean} [quoteSmart=false] Use the other quote if that results in
20+
* less bytes
21+
* @property {boolean} [closeEmptyElements=false] Close elements without any
22+
* content with slash (/) on the opening tag instead of an end tag:
23+
* `<circle />` instead of `<circle></circle>`.
24+
* See `tightClose` to control whether a space is used before the slash.
25+
* @property {boolean} [tightClose=false] Do not use an extra space when closing
26+
* self-closing elements: `<circle/>` instead of `<circle />`.
27+
* @property {boolean} [allowDangerousXml=false] Allow `raw` nodes and insert
28+
* them as raw XML. When falsey, encodes `raw` nodes.
29+
* Only set this if you completely trust the content!
30+
*
31+
* @typedef Context
32+
* @property {Quote} quote
33+
* @property {Quote} alternative
34+
* @property {boolean} close
35+
* @property {boolean} tight
36+
* @property {boolean} dangerous
37+
*
38+
* @callback Handle
39+
* @param {Node} node
40+
* @param {Context} context
41+
* @returns {string}
42+
*/
243

3-
var quotationMark = '"'
4-
var apostrophe = "'"
44+
import {one} from './one.js'
545

6-
// Serialize the given node.
7-
export function toXml(node, options) {
8-
var settings = options || {}
9-
var quote = settings.quote || quotationMark
10-
var alternative = quote === quotationMark ? apostrophe : quotationMark
11-
var smart = settings.quoteSmart
12-
var value =
13-
node && typeof node === 'object' && 'length' in node
14-
? {type: 'root', children: node}
15-
: node
46+
/**
47+
* Serialize the given xast tree (or list of nodes).
48+
*
49+
* @param {Node|Array.<Node>} node
50+
* @param {Options} [options]
51+
* @returns {string}
52+
*/
53+
export function toXml(node, options = {}) {
54+
var quote = options.quote || '"'
55+
/** @type {Quote} */
56+
var alternative = quote === '"' ? "'" : '"'
57+
var smart = options.quoteSmart
58+
/** @type {Node} */
59+
// @ts-ignore Assume no `root` in `node`.
60+
var value = Array.isArray(node) ? {type: 'root', children: node} : node
1661

17-
if (quote !== quotationMark && quote !== apostrophe) {
18-
throw new Error(
19-
'Invalid quote `' +
20-
quote +
21-
'`, expected `' +
22-
apostrophe +
23-
'` or `' +
24-
quotationMark +
25-
'`'
26-
)
62+
if (quote !== '"' && quote !== "'") {
63+
throw new Error('Invalid quote `' + quote + '`, expected `\'` or `"`')
2764
}
2865

2966
return one(value, {
30-
dangerous: settings.allowDangerousXml,
31-
close: settings.closeEmptyElements,
32-
tight: settings.tightClose,
67+
dangerous: options.allowDangerousXml,
68+
close: options.closeEmptyElements,
69+
tight: options.tightClose,
3370
quote,
3471
alternative: smart ? alternative : null
3572
})

lib/instruction.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1+
/**
2+
* @typedef {import('./index.js').Handle} Handle
3+
* @typedef {import('./index.js').Instruction} Instruction
4+
*/
5+
16
import {escape} from './util-escape.js'
27
import {name} from './name.js'
38

49
var unsafe = /\?>/g
510
var subset = ['>']
611

7-
// Serialize a processing instruction.
12+
/**
13+
* Serialize an instruction.
14+
*
15+
* @type {Handle}
16+
* @param {Instruction} node
17+
*/
818
export function instruction(node) {
919
var nodeName = name(node.name) || 'x'
1020
var result = escape(node.value, subset, unsafe)

lib/name.js

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ import {escape} from './util-escape.js'
22

33
var subset = ['\t', '\n', ' ', '"', '&', "'", '/', '<', '=', '>']
44

5+
/**
6+
* Serialize a node name.
7+
*
8+
* @param {string} value
9+
* @returns {string}
10+
*/
511
export function name(value) {
612
return escape(value, subset)
713
}

lib/one.js

+22-13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/**
2+
* @typedef {import('./index.js').Handle} Handle
3+
*/
4+
15
import {all} from './all.js'
26
import {element} from './element.js'
37
import {text} from './text.js'
@@ -9,19 +13,23 @@ import {raw} from './raw.js'
913

1014
var own = {}.hasOwnProperty
1115

12-
var handlers = {}
13-
14-
handlers.root = all
15-
handlers.element = element
16-
handlers.text = text
17-
handlers.comment = comment
18-
handlers.doctype = doctype
19-
handlers.instruction = instruction
20-
handlers.cdata = cdata
21-
handlers.raw = raw
16+
var handlers = {
17+
root: all,
18+
element,
19+
text,
20+
comment,
21+
doctype,
22+
instruction,
23+
cdata,
24+
raw
25+
}
2226

23-
// Serialize one node.
24-
export function one(node, config) {
27+
/**
28+
* Serialize a node.
29+
*
30+
* @type {Handle}
31+
*/
32+
export function one(node, ctx) {
2533
var type = node && node.type
2634

2735
if (!type) {
@@ -32,5 +40,6 @@ export function one(node, config) {
3240
throw new Error('Cannot compile unknown node `' + type + '`')
3341
}
3442

35-
return handlers[type](node, config)
43+
// @ts-ignore Hush, it works.
44+
return handlers[type](node, ctx)
3645
}

lib/raw.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1+
/**
2+
* @typedef {import('./index.js').Handle} Handle
3+
* @typedef {import('./index.js').Raw} Raw
4+
*/
5+
16
import {text} from './text.js'
27

3-
// Serialize raw.
4-
export function raw(node, config) {
5-
return config.dangerous ? node.value : text(node, config)
8+
/**
9+
* Serialize a (non-standard) raw.
10+
*
11+
* @type {Handle}
12+
* @param {Raw} node
13+
*/
14+
export function raw(node, ctx) {
15+
// @ts-ignore Looks like a text.
16+
return ctx.dangerous ? node.value : text(node)
617
}

0 commit comments

Comments
 (0)