Skip to content

Commit b328aa9

Browse files
committed
Change to remove function form of State, use plain object
1 parent 127a488 commit b328aa9

File tree

5 files changed

+82
-159
lines changed

5 files changed

+82
-159
lines changed

lib/footer.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ import {normalizeUri} from 'micromark-util-sanitize-uri'
1717
* `section` element or `undefined`.
1818
*/
1919
export function footer(state) {
20+
const clobberPrefix =
21+
typeof state.options.clobberPrefix === 'string'
22+
? state.options.clobberPrefix
23+
: 'user-content-'
24+
const footnoteBackLabel = state.options.footnoteBackLabel || 'Back to content'
25+
const footnoteLabel = state.options.footnoteLabel || 'Footnotes'
26+
const footnoteLabelTagName = state.options.footnoteLabelTagName || 'h2'
27+
const footnoteLabelProperties = state.options.footnoteLabelProperties || {
28+
className: ['sr-only']
29+
}
2030
/** @type {Array<ElementContent>} */
2131
const listItems = []
2232
let index = -1
@@ -43,13 +53,13 @@ export function footer(state) {
4353
properties: {
4454
href:
4555
'#' +
46-
state.clobberPrefix +
56+
clobberPrefix +
4757
'fnref-' +
4858
safeId +
4959
(referenceIndex > 1 ? '-' + referenceIndex : ''),
5060
dataFootnoteBackref: true,
5161
className: ['data-footnote-backref'],
52-
ariaLabel: state.footnoteBackLabel
62+
ariaLabel: footnoteBackLabel
5363
},
5464
children: [{type: 'text', value: '↩'}]
5565
}
@@ -89,7 +99,7 @@ export function footer(state) {
8999
const listItem = {
90100
type: 'element',
91101
tagName: 'li',
92-
properties: {id: state.clobberPrefix + 'fn-' + safeId},
102+
properties: {id: clobberPrefix + 'fn-' + safeId},
93103
children: state.wrap(content, true)
94104
}
95105

@@ -109,12 +119,12 @@ export function footer(state) {
109119
children: [
110120
{
111121
type: 'element',
112-
tagName: state.footnoteLabelTagName,
122+
tagName: footnoteLabelTagName,
113123
properties: {
114-
...structuredClone(state.footnoteLabelProperties),
124+
...structuredClone(footnoteLabelProperties),
115125
id: 'footnote-label'
116126
},
117-
children: [{type: 'text', value: state.footnoteLabel}]
127+
children: [{type: 'text', value: footnoteLabel}]
118128
},
119129
{type: 'text', value: '\n'},
120130
{

lib/handlers/footnote-reference.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ import {normalizeUri} from 'micromark-util-sanitize-uri'
1717
* hast node.
1818
*/
1919
export function footnoteReference(state, node) {
20+
const clobberPrefix =
21+
typeof state.options.clobberPrefix === 'string'
22+
? state.options.clobberPrefix
23+
: 'user-content-'
2024
const id = String(node.identifier).toUpperCase()
2125
const safeId = normalizeUri(id.toLowerCase())
2226
const index = state.footnoteOrder.indexOf(id)
@@ -39,9 +43,9 @@ export function footnoteReference(state, node) {
3943
type: 'element',
4044
tagName: 'a',
4145
properties: {
42-
href: '#' + state.clobberPrefix + 'fn-' + safeId,
46+
href: '#' + clobberPrefix + 'fn-' + safeId,
4347
id:
44-
state.clobberPrefix +
48+
clobberPrefix +
4549
'fnref-' +
4650
safeId +
4751
(reuseCounter > 1 ? '-' + reuseCounter : ''),

lib/handlers/html.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* hast node.
2121
*/
2222
export function html(state, node) {
23-
if (state.dangerous) {
23+
if (state.options.allowDangerousHtml) {
2424
/** @type {Raw} */
2525
const result = {type: 'raw', value: node.value}
2626
state.patch(node, result)

lib/state.js

Lines changed: 45 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -61,71 +61,33 @@
6161
* @returns {Array<HastElementContent> | HastElementContent | null | undefined}
6262
* hast node.
6363
*
64-
* @callback HFunctionProps
65-
* Signature of `state` for when props are passed.
66-
* @param {MdastNodes | PositionLike | null | undefined} node
67-
* mdast node or unist position.
68-
* @param {string} tagName
69-
* HTML tag name.
70-
* @param {HastProperties} props
71-
* Properties.
72-
* @param {Array<HastElementContent> | null | undefined} [children]
73-
* hast content.
74-
* @returns {HastElement}
75-
* Compiled element.
76-
*
77-
* @callback HFunctionNoProps
78-
* Signature of `state` for when no props are passed.
79-
* @param {MdastNodes | PositionLike | null | undefined} node
80-
* mdast node or unist position.
81-
* @param {string} tagName
82-
* HTML tag name.
83-
* @param {Array<HastElementContent> | null | undefined} [children]
84-
* hast content.
85-
* @returns {HastElement}
86-
* Compiled element.
87-
*
88-
* @typedef HFields
89-
* Info on `state`.
90-
* @property {boolean} dangerous
91-
* Whether HTML is allowed.
92-
* @property {string} clobberPrefix
93-
* Prefix to use to prevent DOM clobbering.
94-
* @property {string} footnoteLabel
95-
* Label to use to introduce the footnote section.
96-
* @property {string} footnoteLabelTagName
97-
* HTML used for the footnote label.
98-
* @property {HastProperties} footnoteLabelProperties
99-
* Properties on the HTML tag used for the footnote label.
100-
* @property {string} footnoteBackLabel
101-
* Label to use from backreferences back to their footnote call.
102-
* @property {(identifier: string) => MdastDefinition | undefined} definition
103-
* Definition cache.
64+
* @typedef State
65+
* Info passed around.
66+
* @property {(node: MdastNodes) => Array<HastElementContent>} all
67+
* Transform the children of an mdast parent to hast.
68+
* @property {<Type extends HastNodes>(from: MdastNodes, to: Type) => HastElement | Type} applyData
69+
* Honor the `data` of `from`, and generate an element instead of `node`.
10470
* @property {Record<string, MdastFootnoteDefinition>} footnoteById
10571
* Footnote definitions by their identifier.
106-
* @property {Array<string>} footnoteOrder
107-
* Identifiers of order when footnote calls first appear in tree order.
10872
* @property {Record<string, number>} footnoteCounts
10973
* Counts for how often the same footnote was called.
74+
* @property {Array<string>} footnoteOrder
75+
* Identifiers of order when footnote calls first appear in tree order.
11076
* @property {Handlers} handlers
11177
* Applied handlers.
112-
* @property {Handler} unknownHandler
113-
* Handler for any none not in `passThrough` or otherwise handled.
114-
* @property {(from: MdastNodes, node: HastNodes) => void} patch
115-
* Copy a node’s positional info.
116-
* @property {<Type extends HastNodes>(from: MdastNodes, to: Type) => HastElement | Type} applyData
117-
* Honor the `data` of `from`, and generate an element instead of `node`.
11878
* @property {(node: MdastNodes, parent: MdastParents | null | undefined) => Array<HastElementContent> | HastElementContent | null | undefined} one
11979
* Transform an mdast node to hast.
120-
* @property {(node: MdastNodes) => Array<HastElementContent>} all
121-
* Transform the children of an mdast parent to hast.
80+
* @property {Options} options
81+
* Configuration.
82+
* @property {(from: MdastNodes, node: HastNodes) => void} patch
83+
* Copy a node’s positional info.
12284
* @property {<Type extends HastRootContent>(nodes: Array<Type>, loose?: boolean | null | undefined) => Array<HastText | Type>} wrap
12385
* Wrap `nodes` with line endings between each node, adds initial/final line endings when `loose`.
124-
* @property {(left: MdastNodeWithData | PositionLike | null | undefined, right: HastElementContent) => HastElementContent} augment
125-
* Like `state` but lower-level and usable on non-elements.
126-
* Deprecated: use `patch` and `applyData`.
127-
* @property {Array<string>} passThrough
128-
* List of node types to pass through untouched (except for their children).
86+
*
87+
* @property {(identifier: string) => MdastDefinition | undefined} definition
88+
* Definition cache.
89+
*
90+
* To do: expose map, document.
12991
*
13092
* @typedef Options
13193
* Configuration (optional).
@@ -158,9 +120,6 @@
158120
*
159121
* @typedef {Record<string, Handler>} Handlers
160122
* Handle nodes.
161-
*
162-
* @typedef {HFields & HFunctionNoProps & HFunctionProps} State
163-
* Info passed around.
164123
*/
165124

166125
import {visit} from 'unist-util-visit'
@@ -182,55 +141,34 @@ const own = {}.hasOwnProperty
182141
*/
183142
export function createState(tree, options) {
184143
const settings = options || {}
185-
const dangerous = settings.allowDangerousHtml || false
186144
/** @type {Record<string, MdastFootnoteDefinition>} */
187145
const footnoteById = {}
188146

189-
// To do: next major: add `options` to state, remove:
190-
// `dangerous`, `clobberPrefix`, `footnoteLabel`, `footnoteLabelTagName`,
191-
// `footnoteLabelProperties`, `footnoteBackLabel`, `passThrough`,
192-
// `unknownHandler`.
193-
194-
// To do: next major: move to `state.options.allowDangerousHtml`.
195-
state.dangerous = dangerous
196-
// To do: next major: move to `state.options`.
197-
state.clobberPrefix =
198-
settings.clobberPrefix === null || settings.clobberPrefix === undefined
199-
? 'user-content-'
200-
: settings.clobberPrefix
201-
// To do: next major: move to `state.options`.
202-
state.footnoteLabel = settings.footnoteLabel || 'Footnotes'
203-
// To do: next major: move to `state.options`.
204-
state.footnoteLabelTagName = settings.footnoteLabelTagName || 'h2'
205-
// To do: next major: move to `state.options`.
206-
state.footnoteLabelProperties = settings.footnoteLabelProperties || {
207-
className: ['sr-only']
147+
/** @type {State} */
148+
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),
156+
footnoteById,
157+
/** @type {Array<string>} */
158+
footnoteOrder: [],
159+
/** @type {Record<string, number>} */
160+
footnoteCounts: {},
161+
162+
patch,
163+
applyData,
164+
// @ts-expect-error: fix `null` handling.
165+
one: oneBound,
166+
all: allBound,
167+
// @ts-expect-error: fix `null` handling.
168+
wrap,
169+
// To do: next major: remove `augment`.
170+
augment
208171
}
209-
// To do: next major: move to `state.options`.
210-
state.footnoteBackLabel = settings.footnoteBackLabel || 'Back to content'
211-
// To do: next major: move to `state.options`.
212-
state.unknownHandler = settings.unknownHandler
213-
// To do: next major: move to `state.options`.
214-
state.passThrough = settings.passThrough
215-
216-
state.handlers = {...handlers, ...settings.handlers}
217-
218-
// To do: next major: replace utility with `definitionById` object, so we
219-
// only walk once (as we need footnotes too).
220-
state.definition = definitions(tree)
221-
state.footnoteById = footnoteById
222-
/** @type {Array<string>} */
223-
state.footnoteOrder = []
224-
/** @type {Record<string, number>} */
225-
state.footnoteCounts = {}
226-
227-
state.patch = patch
228-
state.applyData = applyData
229-
state.one = oneBound
230-
state.all = allBound
231-
state.wrap = wrap
232-
// To do: next major: remove `augment`.
233-
state.augment = augment
234172

235173
visit(tree, 'footnoteDefinition', function (definition) {
236174
const id = String(definition.identifier).toUpperCase()
@@ -242,8 +180,6 @@ export function createState(tree, options) {
242180
}
243181
})
244182

245-
// @ts-expect-error Hush, it’s fine!
246-
// To do: a cleaned state should allow this?
247183
return state
248184

249185
/**
@@ -299,29 +235,6 @@ export function createState(tree, options) {
299235
}
300236
/* c8 ignore stop */
301237

302-
/**
303-
* Create an element for `node`.
304-
*
305-
* @type {HFunctionProps}
306-
*/
307-
/* c8 ignore start */
308-
// To do: next major: remove.
309-
function state(node, tagName, props, children) {
310-
if (Array.isArray(props)) {
311-
children = props
312-
props = {}
313-
}
314-
315-
// @ts-expect-error augmenting an element yields an element.
316-
return augment(node, {
317-
type: 'element',
318-
tagName,
319-
properties: props || {},
320-
children: children || []
321-
})
322-
}
323-
/* c8 ignore stop */
324-
325238
/**
326239
* Transform an mdast node into a hast node.
327240
*
@@ -333,7 +246,6 @@ export function createState(tree, options) {
333246
* Resulting hast node.
334247
*/
335248
function oneBound(node, parent) {
336-
// @ts-expect-error: that’s a state :)
337249
return one(state, node, parent)
338250
}
339251

@@ -346,7 +258,6 @@ export function createState(tree, options) {
346258
* Resulting hast nodes.
347259
*/
348260
function allBound(parent) {
349-
// @ts-expect-error: that’s a state :)
350261
return all(state, parent)
351262
}
352263
}
@@ -449,23 +360,21 @@ function applyData(from, to) {
449360
*/
450361
// To do: next major: do not expose, keep bound.
451362
export function one(state, node, parent) {
452-
const type = node && node.type
363+
const type = node.type
453364

454365
if (own.call(state.handlers, type)) {
455366
return state.handlers[type](state, node, parent)
456367
}
457368

458-
if (state.passThrough && state.passThrough.includes(type)) {
369+
if (state.options.passThrough && state.options.passThrough.includes(type)) {
459370
// To do: next major: deep clone.
460371
// @ts-expect-error: types of passed through nodes are expected to be added manually.
461372
return 'children' in node ? {...node, children: all(state, node)} : node
462373
}
463374

464-
if (state.unknownHandler) {
465-
return state.unknownHandler(state, node, parent)
466-
}
375+
const unknown = state.options.unknownHandler || defaultUnknownHandler
467376

468-
return defaultUnknownHandler(state, node)
377+
return unknown(state, node, parent)
469378
}
470379

471380
/**

readme.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -282,27 +282,27 @@ Info passed around about the current state (TypeScript type).
282282

283283
###### Fields
284284

285-
<!-- To do: add `options`, alternative to `definition`. -->
286-
287-
* `patch` (`(from: MdastNode, to: HastNode) => undefined`)
288-
— copy a node’s positional info
285+
* `all` (`(node: MdastNode) => Array<HastNode>`)
286+
— transform the children of an mdast parent to hast
289287
* `applyData` (`<Type extends HastNode>(from: MdastNode, to: Type) => Type | HastElement`)
290288
— honor the `data` of `from` and maybe generate an element instead of `to`
289+
* `footnoteById` (`Record<string, MdastFootnoteDefinition>`)
290+
— footnote definitions by their uppercased identifier
291+
* `footnoteCounts` (`Record<string, number>`)
292+
— counts for how often the same footnote was called
293+
* `footnoteOrder` (`Array<string>`)
294+
— identifiers of order when footnote calls first appear in tree order
295+
* `handlers` ([`Handlers`][api-handlers])
296+
— applied node handlers
291297
* `one` (`(node: MdastNode, parent: MdastNode | undefined) => HastNode | Array<HastNode> | undefined`)
292298
— transform an mdast node to hast
293-
* `all` (`(node: MdastNode) => Array<HastNode>`)
294-
— transform the children of an mdast parent to hast
299+
* `options` ([`Options`][api-options])
300+
— configuration
301+
* `patch` (`(from: MdastNode, to: HastNode) => undefined`)
302+
— copy a node’s positional info
295303
* `wrap` (`<Type extends HastNode>(nodes: Array<Type>, loose?: boolean) => Array<Type | HastText>`)
296304
— wrap `nodes` with line endings between each node, adds initial/final line
297305
endings when `loose`
298-
* `handlers` ([`Handlers`][api-handlers])
299-
— applied node handlers
300-
* `footnoteById` (`Record<string, MdastFootnoteDefinition>`)
301-
— footnote definitions by their uppercased identifier
302-
* `footnoteOrder` (`Array<string>`)
303-
— identifiers of order when footnote calls first appear in tree order
304-
* `footnoteCounts` (`Record<string, number>`)
305-
— counts for how often the same footnote was called
306306

307307
## Examples
308308

0 commit comments

Comments
 (0)