Skip to content

Commit 72b8a68

Browse files
committed
Change to use maps for definitions on state
1 parent b328aa9 commit 72b8a68

File tree

8 files changed

+54
-103
lines changed

8 files changed

+54
-103
lines changed

lib/footer.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export function footer(state) {
3232
let index = -1
3333

3434
while (++index < state.footnoteOrder.length) {
35-
const def = state.footnoteById[state.footnoteOrder[index]]
35+
const def = state.footnoteById.get(state.footnoteOrder[index])
3636

3737
if (!def) {
3838
continue
@@ -44,8 +44,10 @@ export function footer(state) {
4444
let referenceIndex = 0
4545
/** @type {Array<ElementContent>} */
4646
const backReferences = []
47+
const counts = state.footnoteCounts.get(id)
4748

48-
while (++referenceIndex <= state.footnoteCounts[id]) {
49+
// eslint-disable-next-line no-unmodified-loop-condition
50+
while (counts !== undefined && ++referenceIndex <= counts) {
4951
/** @type {Element} */
5052
const backReference = {
5153
type: 'element',

lib/handlers/footnote-reference.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,18 @@ export function footnoteReference(state, node) {
2727
/** @type {number} */
2828
let counter
2929

30-
if (index === -1) {
30+
let reuseCounter = state.footnoteCounts.get(id)
31+
32+
if (reuseCounter === undefined) {
33+
reuseCounter = 0
3134
state.footnoteOrder.push(id)
32-
state.footnoteCounts[id] = 1
3335
counter = state.footnoteOrder.length
3436
} else {
35-
state.footnoteCounts[id]++
3637
counter = index + 1
3738
}
3839

39-
const reuseCounter = state.footnoteCounts[id]
40+
reuseCounter += 1
41+
state.footnoteCounts.set(id, reuseCounter)
4042

4143
/** @type {Element} */
4244
const link = {

lib/handlers/footnote.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/**
22
* @typedef {import('hast').Element} Element
3+
* @typedef {import('mdast').FootnoteDefinition} FootnoteDefinition
34
* @typedef {import('mdast').Node} Node
45
* @typedef {import('../state.js').State} State
56
*/
@@ -23,21 +24,22 @@ import {footnoteReference} from './footnote-reference.js'
2324
* hast node.
2425
*/
2526
export function footnote(state, node) {
26-
const footnoteById = state.footnoteById
2727
let no = 1
2828

29-
while (no in footnoteById) no++
29+
while (state.footnoteById.get(String(no))) no++
3030

3131
const identifier = String(no)
32-
33-
footnoteById[identifier] = {
32+
/** @type {FootnoteDefinition} */
33+
const definition = {
3434
type: 'footnoteDefinition',
3535
identifier,
3636
// @ts-expect-error: to do: remove this.
3737
children: [{type: 'paragraph', children: node.children}],
3838
position: node.position
3939
}
4040

41+
state.footnoteById.set(identifier, definition)
42+
4143
return footnoteReference(state, {
4244
type: 'footnoteReference',
4345
identifier,

lib/handlers/image-reference.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import {revert} from '../revert.js'
2020
* hast node.
2121
*/
2222
export function imageReference(state, node) {
23-
const def = state.definition(node.identifier)
23+
const id = String(node.identifier).toUpperCase()
24+
const def = state.definitionById.get(id)
2425

2526
if (!def) {
2627
return revert(state, node)

lib/handlers/link-reference.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import {revert} from '../revert.js'
2020
* hast node.
2121
*/
2222
export function linkReference(state, node) {
23-
const def = state.definition(node.identifier)
23+
const id = String(node.identifier).toUpperCase()
24+
const def = state.definitionById.get(id)
2425

2526
if (!def) {
2627
return revert(state, node)

lib/state.js

Lines changed: 30 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,11 @@
6767
* Transform the children of an mdast parent to hast.
6868
* @property {<Type extends HastNodes>(from: MdastNodes, to: Type) => HastElement | Type} applyData
6969
* Honor the `data` of `from`, and generate an element instead of `node`.
70-
* @property {Record<string, MdastFootnoteDefinition>} footnoteById
70+
* @property {Map<string, MdastDefinition>} definitionById
71+
* Definitions by their identifier.
72+
* @property {Map<string, MdastFootnoteDefinition>} footnoteById
7173
* Footnote definitions by their identifier.
72-
* @property {Record<string, number>} footnoteCounts
74+
* @property {Map<string, number>} footnoteCounts
7375
* Counts for how often the same footnote was called.
7476
* @property {Array<string>} footnoteOrder
7577
* Identifiers of order when footnote calls first appear in tree order.
@@ -84,11 +86,6 @@
8486
* @property {<Type extends HastRootContent>(nodes: Array<Type>, loose?: boolean | null | undefined) => Array<HastText | Type>} wrap
8587
* Wrap `nodes` with line endings between each node, adds initial/final line endings when `loose`.
8688
*
87-
* @property {(identifier: string) => MdastDefinition | undefined} definition
88-
* Definition cache.
89-
*
90-
* To do: expose map, document.
91-
*
9289
* @typedef Options
9390
* Configuration (optional).
9491
* @property {boolean | null | undefined} [allowDangerousHtml=false]
@@ -123,8 +120,7 @@
123120
*/
124121

125122
import {visit} from 'unist-util-visit'
126-
import {pointEnd, pointStart, position} from 'unist-util-position'
127-
import {definitions} from 'mdast-util-definitions'
123+
import {position} from 'unist-util-position'
128124
import {handlers} from './handlers/index.js'
129125

130126
const own = {}.hasOwnProperty
@@ -141,100 +137,47 @@ const own = {}.hasOwnProperty
141137
*/
142138
export function createState(tree, options) {
143139
const settings = options || {}
144-
/** @type {Record<string, MdastFootnoteDefinition>} */
145-
const footnoteById = {}
140+
/** @type {Map<string, MdastDefinition>} */
141+
const definitionById = new Map()
142+
/** @type {Map<string, MdastFootnoteDefinition>} */
143+
const footnoteById = new Map()
144+
/** @type {Map<string, number>} */
145+
const footnoteCounts = new Map()
146146

147147
/** @type {State} */
148148
const state = {
149-
options: settings,
150-
// @ts-expect-error: fix `null` handling?
151-
handlers: {...handlers, ...settings.handlers},
152-
153-
// To do: next major: replace utility with `definitionById` object, so we
154-
// only walk once (as we need footnotes too).
155-
definition: definitions(tree),
149+
all: allBound,
150+
applyData,
151+
definitionById,
156152
footnoteById,
157-
/** @type {Array<string>} */
153+
footnoteCounts,
158154
footnoteOrder: [],
159-
/** @type {Record<string, number>} */
160-
footnoteCounts: {},
161-
162-
patch,
163-
applyData,
155+
// @ts-expect-error: fix `null` handling?
156+
handlers: {...handlers, ...settings.handlers},
164157
// @ts-expect-error: fix `null` handling.
165158
one: oneBound,
166-
all: allBound,
159+
options: settings,
160+
patch,
167161
// @ts-expect-error: fix `null` handling.
168-
wrap,
169-
// To do: next major: remove `augment`.
170-
augment
162+
wrap
171163
}
172164

173-
visit(tree, 'footnoteDefinition', function (definition) {
174-
const id = String(definition.identifier).toUpperCase()
165+
visit(tree, function (node) {
166+
if (node.type === 'definition' || node.type === 'footnoteDefinition') {
167+
const map = node.type === 'definition' ? definitionById : footnoteById
168+
const id = String(node.identifier).toUpperCase()
175169

176-
// Mimick CM behavior of link definitions.
177-
// See: <https://github.com/syntax-tree/mdast-util-definitions/blob/8290999/index.js#L26>.
178-
if (!own.call(footnoteById, id)) {
179-
footnoteById[id] = definition
170+
// Mimick CM behavior of link definitions.
171+
// See: <https://github.com/syntax-tree/mdast-util-definitions/blob/9032189/lib/index.js#L20-L21>.
172+
if (!map.has(id)) {
173+
// @ts-expect-error: node type matches map.
174+
map.set(id, node)
175+
}
180176
}
181177
})
182178

183179
return state
184180

185-
/**
186-
* Finalise the created `right`, a hast node, from `left`, an mdast node.
187-
*
188-
* @param {MdastNodeWithData | PositionLike | null | undefined} left
189-
* @param {HastElementContent} right
190-
* @returns {HastElementContent}
191-
*/
192-
/* c8 ignore start */
193-
// To do: next major: remove.
194-
function augment(left, right) {
195-
// Handle `data.hName`, `data.hProperties, `data.hChildren`.
196-
if (left && 'data' in left && left.data) {
197-
/** @type {MdastData} */
198-
const data = left.data
199-
200-
if (data.hName) {
201-
if (right.type !== 'element') {
202-
right = {
203-
type: 'element',
204-
tagName: '',
205-
properties: {},
206-
children: []
207-
}
208-
}
209-
210-
right.tagName = data.hName
211-
}
212-
213-
if (right.type === 'element' && data.hProperties) {
214-
right.properties = {...right.properties, ...data.hProperties}
215-
}
216-
217-
if ('children' in right && right.children && data.hChildren) {
218-
right.children = data.hChildren
219-
}
220-
}
221-
222-
if (left) {
223-
const ctx = 'type' in left ? left : {position: left}
224-
// @ts-expect-error: fine, can be removed when this function is removed.
225-
const start = pointStart(ctx)
226-
// @ts-expect-error: fine, can be removed when this function is removed.
227-
const end = pointEnd(ctx)
228-
229-
if (start && end) {
230-
right.position = {start, end}
231-
}
232-
}
233-
234-
return right
235-
}
236-
/* c8 ignore stop */
237-
238181
/**
239182
* Transform an mdast node into a hast node.
240183
*

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
"@types/mdast": "^4.0.0",
3939
"@ungap/structured-clone": "^1.0.0",
4040
"devlop": "^1.0.0",
41-
"mdast-util-definitions": "^6.0.0",
4241
"micromark-util-sanitize-uri": "^2.0.0",
4342
"trim-lines": "^3.0.0",
4443
"unist-util-position": "^5.0.0",

readme.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -286,9 +286,11 @@ Info passed around about the current state (TypeScript type).
286286
— transform the children of an mdast parent to hast
287287
* `applyData` (`<Type extends HastNode>(from: MdastNode, to: Type) => Type | HastElement`)
288288
— honor the `data` of `from` and maybe generate an element instead of `to`
289-
* `footnoteById` (`Record<string, MdastFootnoteDefinition>`)
289+
* `definitionById` (`Map<string, Definition>`)
290+
— definitions by their uppercased identifier
291+
* `footnoteById` (`Map<string, FootnoteDefinition>`)
290292
— footnote definitions by their uppercased identifier
291-
* `footnoteCounts` (`Record<string, number>`)
293+
* `footnoteCounts` (`Map<string, number>`)
292294
— counts for how often the same footnote was called
293295
* `footnoteOrder` (`Array<string>`)
294296
— identifiers of order when footnote calls first appear in tree order
@@ -299,7 +301,6 @@ Info passed around about the current state (TypeScript type).
299301
* `options` ([`Options`][api-options])
300302
— configuration
301303
* `patch` (`(from: MdastNode, to: HastNode) => undefined`)
302-
— copy a node’s positional info
303304
* `wrap` (`<Type extends HastNode>(nodes: Array<Type>, loose?: boolean) => Array<Type | HastText>`)
304305
— wrap `nodes` with line endings between each node, adds initial/final line
305306
endings when `loose`

0 commit comments

Comments
 (0)