Skip to content

Commit e3aa39c

Browse files
committed
Replace nodeById with state.elementById
Previously, `nodeById` was a plain object, which had uppercased IDs as keys and elements as values. This commit replaces that with `elementById`, which is a `Map`, where IDs are case-sensitive.
1 parent 9bf96b9 commit e3aa39c

File tree

5 files changed

+95
-100
lines changed

5 files changed

+95
-100
lines changed

lib/handlers/input.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ export function input(state, node) {
7878
properties.type !== 'button' &&
7979
properties.list
8080
) {
81-
const list = String(properties.list).toUpperCase()
82-
const datalist = list in state.nodeById ? state.nodeById[list] : undefined
81+
const list = String(properties.list)
82+
const datalist = state.elementById.get(list)
8383

8484
if (datalist && datalist.tagName === 'datalist') {
8585
values = findSelectedOptions(state, datalist, properties)

lib/handlers/media.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/**
22
* @typedef {import('hast').Element} Element
3+
* @typedef {import('mdast').Root} Root
34
* @typedef {import('mdast').Link} Link
45
* @typedef {import('mdast').Image} Image
56
* @typedef {import('mdast').Content} MdastContent
@@ -27,7 +28,15 @@ export function media(state, node) {
2728
let linkInFallbackContent = false
2829
let nodes = state.all(node)
2930

30-
visit({type: 'root', children: nodes}, 'link', findLink)
31+
/** @type {Root} */
32+
const fragment = {type: 'root', children: nodes}
33+
34+
visit(fragment, function (node) {
35+
if (node.type === 'link') {
36+
linkInFallbackContent = true
37+
return EXIT
38+
}
39+
})
3140

3241
// If the content links to something, or if it’s not phrasing…
3342
if (linkInFallbackContent || wrapNeeded(nodes)) {
@@ -71,9 +80,4 @@ export function media(state, node) {
7180
}
7281
state.patch(node, result)
7382
return result
74-
75-
function findLink() {
76-
linkInFallbackContent = true
77-
return EXIT
78-
}
7983
}

lib/handlers/table.js

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -143,42 +143,44 @@ function inspect(node) {
143143
let rowIndex = 0
144144
let cellIndex = 0
145145

146-
visit(node, 'element', (child) => {
147-
// Don’t enter nested tables.
148-
if (child.tagName === 'table' && node !== child) {
149-
return SKIP
150-
}
146+
visit(node, function (child) {
147+
if (child.type === 'element') {
148+
// Don’t enter nested tables.
149+
if (child.tagName === 'table' && node !== child) {
150+
return SKIP
151+
}
151152

152-
if (
153-
(child.tagName === 'th' || child.tagName === 'td') &&
154-
child.properties
155-
) {
156-
if (!info.align[cellIndex]) {
157-
const value = String(child.properties.align || '') || null
158-
159-
if (
160-
value === null ||
161-
value === 'left' ||
162-
value === 'center' ||
163-
value === 'right'
164-
) {
165-
info.align[cellIndex] = value
153+
if (
154+
(child.tagName === 'th' || child.tagName === 'td') &&
155+
child.properties
156+
) {
157+
if (!info.align[cellIndex]) {
158+
const value = String(child.properties.align || '') || null
159+
160+
if (
161+
value === null ||
162+
value === 'left' ||
163+
value === 'center' ||
164+
value === 'right'
165+
) {
166+
info.align[cellIndex] = value
167+
}
166168
}
167-
}
168169

169-
// If there is a `th` in the first row, assume there is a header row.
170-
if (info.headless && rowIndex < 2 && child.tagName === 'th') {
170+
// If there is a `th` in the first row, assume there is a header row.
171+
if (info.headless && rowIndex < 2 && child.tagName === 'th') {
172+
info.headless = false
173+
}
174+
175+
cellIndex++
176+
}
177+
// If there is a `thead`, assume there is a header row.
178+
else if (child.tagName === 'thead') {
171179
info.headless = false
180+
} else if (child.tagName === 'tr') {
181+
rowIndex++
182+
cellIndex = 0
172183
}
173-
174-
cellIndex++
175-
}
176-
// If there is a `thead`, assume there is a header row.
177-
else if (child.tagName === 'thead') {
178-
info.headless = false
179-
} else if (child.tagName === 'tr') {
180-
rowIndex++
181-
cellIndex = 0
182184
}
183185
})
184186

lib/index.js

Lines changed: 49 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,13 @@ import {all} from './all.js'
3333
*/
3434
export function toMdast(tree, options) {
3535
const options_ = options || {}
36-
/** @type {Record<string, Element>} */
37-
const byId = Object.create(null)
3836
/** @type {State} */
3937
const state = {
4038
patch,
4139
all: allBound,
4240
one: oneBound,
4341
options: options_,
44-
nodeById: byId,
42+
elementById: new Map(),
4543
handlers: options_.handlers
4644
? {...handlers, ...options_.handlers}
4745
: handlers,
@@ -53,14 +51,13 @@ export function toMdast(tree, options) {
5351
/** @type {MdastNode | MdastRoot} */
5452
let mdast
5553

56-
visit(tree, 'element', (node) => {
57-
const id =
58-
node.properties &&
59-
'id' in node.properties &&
60-
String(node.properties.id).toUpperCase()
54+
visit(tree, function (node) {
55+
if (node && node.type === 'element' && node.properties) {
56+
const id = String(node.properties.id || '') || undefined
6157

62-
if (id && !(id in byId)) {
63-
byId[id] = node
58+
if (id && !state.elementById.has(id)) {
59+
state.elementById.set(id, node)
60+
}
6461
}
6562
})
6663

@@ -79,63 +76,55 @@ export function toMdast(tree, options) {
7976
mdast = result
8077
}
8178

82-
visit(mdast, 'text', ontext)
83-
84-
return mdast
85-
86-
/**
87-
* Collapse text nodes, and fix whitespace.
88-
* Most of this is taken care of by `rehype-minify-whitespace`, but
89-
* we’re generating some whitespace too, and some nodes are in the end
90-
* ignored.
91-
* So clean up.
92-
*
93-
* @type {import('unist-util-visit/complex-types.js').BuildVisitor<MdastRoot, 'text'>}
94-
*/
95-
function ontext(node, index, parent) {
96-
/* c8 ignore next 3 */
97-
if (index === null || !parent) {
98-
return
99-
}
100-
101-
const previous = parent.children[index - 1]
102-
103-
if (previous && previous.type === node.type) {
104-
previous.value += node.value
105-
parent.children.splice(index, 1)
106-
107-
if (previous.position && node.position) {
108-
previous.position.end = node.position.end
79+
// Collapse text nodes, and fix whitespace.
80+
//
81+
// Most of this is taken care of by `rehype-minify-whitespace`, but
82+
// we’re generating some whitespace too, and some nodes are in the end
83+
// ignored.
84+
// So clean up.
85+
visit(mdast, function (node, index, parent) {
86+
if (node.type === 'text' && index !== null && parent) {
87+
const previous = parent.children[index - 1]
88+
89+
if (previous && previous.type === node.type) {
90+
previous.value += node.value
91+
parent.children.splice(index, 1)
92+
93+
if (previous.position && node.position) {
94+
previous.position.end = node.position.end
95+
}
96+
97+
// Iterate over the previous node again, to handle its total value.
98+
return index - 1
10999
}
110100

111-
// Iterate over the previous node again, to handle its total value.
112-
return index - 1
113-
}
114-
115-
node.value = node.value.replace(/[\t ]*(\r?\n|\r)[\t ]*/, '$1')
116-
117-
// We don’t care about other phrasing nodes in between (e.g., `[ asd ]()`),
118-
// as there the whitespace matters.
119-
if (
120-
parent &&
121-
(parent.type === 'heading' ||
122-
parent.type === 'paragraph' ||
123-
parent.type === 'root')
124-
) {
125-
if (!index) {
126-
node.value = node.value.replace(/^[\t ]+/, '')
101+
node.value = node.value.replace(/[\t ]*(\r?\n|\r)[\t ]*/, '$1')
102+
103+
// We don’t care about other phrasing nodes in between (e.g., `[ asd ]()`),
104+
// as there the whitespace matters.
105+
if (
106+
parent &&
107+
(parent.type === 'heading' ||
108+
parent.type === 'paragraph' ||
109+
parent.type === 'root')
110+
) {
111+
if (!index) {
112+
node.value = node.value.replace(/^[\t ]+/, '')
113+
}
114+
115+
if (index === parent.children.length - 1) {
116+
node.value = node.value.replace(/[\t ]+$/, '')
117+
}
127118
}
128119

129-
if (index === parent.children.length - 1) {
130-
node.value = node.value.replace(/[\t ]+$/, '')
120+
if (!node.value) {
121+
parent.children.splice(index, 1)
122+
return index
131123
}
132124
}
125+
})
133126

134-
if (!node.value) {
135-
parent.children.splice(index, 1)
136-
return index
137-
}
138-
}
127+
return mdast
139128
}
140129

141130
export {handlers as defaultHandlers} from './handlers/index.js'

lib/types.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
* Transform a hast node to mdast.
6262
* @property {Options} options
6363
* User configuration.
64-
* @property {Record<string, Element>} nodeById
64+
* @property {Map<string, Element>} elementById
6565
* Elements by their `id`.
6666
* @property {Record<string, Handle>} handlers
6767
* Applied handlers.

0 commit comments

Comments
 (0)