1
1
/**
2
+ * @typedef {import('hast').Comment } Comment
3
+ * @typedef {import('hast').Doctype } Doctype
4
+ * @typedef {import('hast').Element } Element
5
+ * @typedef {import('hast').Nodes } Nodes
6
+ * @typedef {import('hast').Root } Root
7
+ * @typedef {import('hast').RootContent } RootContent
8
+ * @typedef {import('hast').Text } Text
9
+ *
10
+ * @typedef {import('mdast-util-to-hast').Raw } Raw
11
+ *
2
12
* @typedef {import('parse5').DefaultTreeAdapterMap } DefaultTreeAdapterMap
13
+ * @typedef {import('parse5').ParserOptions<DefaultTreeAdapterMap> } ParserOptions
3
14
* @typedef {import('parse5').Token.CharacterToken } CharacterToken
4
15
* @typedef {import('parse5').Token.CommentToken } CommentToken
5
16
* @typedef {import('parse5').Token.DoctypeToken } DoctypeToken
6
- * @typedef {import('parse5').Token.TagToken } TagToken
7
17
* @typedef {import('parse5').Token.Location } Location
8
- * @typedef {import('parse5').ParserOptions<DefaultTreeAdapterMap> } ParserOptions
9
- *
10
- * @typedef {import('vfile').VFile } VFile
18
+ * @typedef {import('parse5').Token.TagToken } TagToken
11
19
*
12
20
* @typedef {import('unist').Point } Point
13
21
*
14
- * @typedef {import('hast').Root } Root
15
- * @typedef {import('hast').Doctype } Doctype
16
- * @typedef {import('hast').Element } Element
17
- * @typedef {import('hast').Text } Text
18
- * @typedef {import('hast').Comment } Comment
19
- * @typedef {import('hast').RootContent } RootContent
20
- * @typedef {import('hast').Nodes } Nodes
21
- *
22
- * @typedef {import('mdast-util-to-hast').Raw } Raw
22
+ * @typedef {import('vfile').VFile } VFile
23
23
*/
24
24
25
25
/**
26
- * @typedef {{type: 'comment', value: {stitch: Nodes}} } Stitch
27
- *
28
26
* @typedef Options
29
27
* Configuration.
28
+ * @property {VFile | null | undefined } [file]
29
+ * Corresponding virtual file representing the input document (optional).
30
30
* @property {Array<string> | null | undefined } [passThrough]
31
- * List of custom hast node types to pass through (keep).
31
+ * List of custom hast node types to pass through (as in, keep) (optional ).
32
32
*
33
33
* If the passed through nodes have children, those children are expected to
34
34
* be hast again and will be handled.
35
- * @property {VFile | null | undefined } [file]
36
- * Corresponding virtual file representing the input document.
37
35
*
38
36
* @typedef State
39
37
* Info passed around about the current state.
38
+ * @property {(node: Nodes) => undefined } handle
39
+ * Add a hast node to the parser.
40
+ * @property {Options } options
41
+ * User configuration.
40
42
* @property {Parser<DefaultTreeAdapterMap> } parser
41
43
* Current parser.
42
- * @property {(node: Nodes) => void } handle
43
- * Add a hast node to the parser.
44
44
* @property {boolean } stitches
45
45
* Whether there are stitches.
46
- * @property {Options } options
47
- * User configuration.
46
+ *
47
+ * @typedef {{type: 'comment', value: {stitch: Nodes}} } Stitch
48
+ * Custom comment-like value we pass through parse5, which contains a
49
+ * replacement node that we’ll swap back in afterwards.
48
50
*/
49
51
50
52
import extend from 'extend'
51
53
import { fromParse5 } from 'hast-util-from-parse5'
52
54
import { toParse5 } from 'hast-util-to-parse5'
53
55
import { htmlVoidElements } from 'html-void-elements'
54
56
import { Parser , Token , TokenizerMode , html } from 'parse5'
55
- import { pointStart , pointEnd } from 'unist-util-position'
57
+ import { pointEnd , pointStart } from 'unist-util-position'
56
58
import { visit } from 'unist-util-visit'
57
- import { zwitch } from 'zwitch'
58
59
import { webNamespaces } from 'web-namespaces'
60
+ import { zwitch } from 'zwitch'
59
61
60
62
// Node types associated with MDX.
61
- // <https://github.com/mdx-js/mdx/blob/641eb91 /packages/mdx/lib/node-types.js>
63
+ // <https://github.com/mdx-js/mdx/blob/8a56312 /packages/mdx/lib/node-types.js>
62
64
const knownMdxNames = new Set ( [
63
65
'mdxFlowExpression' ,
64
66
'mdxJsxFlowElement' ,
@@ -77,13 +79,13 @@ const parseOptions = {sourceCodeLocationInfo: true, scriptingEnabled: false}
77
79
* @param {Nodes } tree
78
80
* Original hast tree to transform.
79
81
* @param {Options | null | undefined } [options]
80
- * Configuration.
82
+ * Configuration (optional) .
81
83
* @returns {Nodes }
82
84
* Parsed again tree.
83
85
*/
84
86
export function raw ( tree , options ) {
85
87
const document = documentMode ( tree )
86
- /** @type {(node: Nodes, state: State) => void } */
88
+ /** @type {(node: Nodes, state: State) => undefined } */
87
89
const one = zwitch ( 'type' , {
88
90
handlers : { root, element, text, comment, doctype, raw : handleRaw } ,
89
91
unknown
@@ -93,7 +95,7 @@ export function raw(tree, options) {
93
95
const state = {
94
96
parser : document
95
97
? new Parser ( parseOptions )
96
- : Parser . getFragmentParser ( null , parseOptions ) ,
98
+ : Parser . getFragmentParser ( undefined , parseOptions ) ,
97
99
handle ( node ) {
98
100
one ( node , state )
99
101
} ,
@@ -111,11 +113,13 @@ export function raw(tree, options) {
111
113
} )
112
114
113
115
if ( state . stitches ) {
114
- visit ( result , 'comment' , ( node , index , parent ) => {
116
+ visit ( result , 'comment' , function ( node , index , parent ) {
115
117
const stitch = /** @type {Stitch } */ ( /** @type {unknown } */ ( node ) )
116
- if ( stitch . value . stitch && parent !== null && index !== null ) {
118
+ if ( stitch . value . stitch && parent && index !== undefined ) {
119
+ /** @type {Array<RootContent> } */
120
+ const siblings = parent . children
117
121
// @ts -expect-error: assume the stitch is allowed.
118
- parent . children [ index ] = stitch . value . stitch
122
+ siblings [ index ] = stitch . value . stitch
119
123
return index
120
124
}
121
125
} )
@@ -140,7 +144,7 @@ export function raw(tree, options) {
140
144
* hast content.
141
145
* @param {State } state
142
146
* Info passed around about the current state.
143
- * @returns {void }
147
+ * @returns {undefined }
144
148
* Nothing.
145
149
*/
146
150
function all ( nodes , state ) {
@@ -161,7 +165,7 @@ function all(nodes, state) {
161
165
* hast root node.
162
166
* @param {State } state
163
167
* Info passed around about the current state.
164
- * @returns {void }
168
+ * @returns {undefined }
165
169
* Nothing.
166
170
*/
167
171
function root ( node , state ) {
@@ -175,7 +179,7 @@ function root(node, state) {
175
179
* hast element node.
176
180
* @param {State } state
177
181
* Info passed around about the current state.
178
- * @returns {void }
182
+ * @returns {undefined }
179
183
* Nothing.
180
184
*/
181
185
function element ( node , state ) {
@@ -193,7 +197,7 @@ function element(node, state) {
193
197
* hast text node.
194
198
* @param {State } state
195
199
* Info passed around about the current state.
196
- * @returns {void }
200
+ * @returns {undefined }
197
201
* Nothing.
198
202
*/
199
203
function text ( node , state ) {
@@ -220,7 +224,7 @@ function text(node, state) {
220
224
* hast doctype node.
221
225
* @param {State } state
222
226
* Info passed around about the current state.
223
- * @returns {void }
227
+ * @returns {undefined }
224
228
* Nothing.
225
229
*/
226
230
function doctype ( node , state ) {
@@ -250,7 +254,7 @@ function doctype(node, state) {
250
254
* unknown node.
251
255
* @param {State } state
252
256
* Info passed around about the current state.
253
- * @returns {void }
257
+ * @returns {undefined }
254
258
* Nothing.
255
259
*/
256
260
function stitch ( node , state ) {
@@ -263,8 +267,10 @@ function stitch(node, state) {
263
267
// Recurse, because to somewhat handle `[<x>]</x>` (where `[]` denotes the
264
268
// passed through node).
265
269
if ( 'children' in node && 'children' in clone ) {
266
- const fakeRoot = raw ( { type : 'root' , children : node . children } , state . options )
267
- // @ts -expect-error Assume a given parent yields a parent.
270
+ // Root in root out.
271
+ const fakeRoot = /** @type {Root } */ (
272
+ raw ( { type : 'root' , children : node . children } , state . options )
273
+ )
268
274
clone . children = fakeRoot . children
269
275
}
270
276
@@ -281,12 +287,12 @@ function stitch(node, state) {
281
287
* hast comment node.
282
288
* @param {State } state
283
289
* Info passed around about the current state.
284
- * @returns {void }
290
+ * @returns {undefined }
285
291
* Nothing.
286
292
*/
287
293
function comment ( node , state ) {
288
294
/** @type {string } */
289
- // @ts -expect-error: yeah, we’re passing stiches through.
295
+ // @ts -expect-error: we pass stitches through.
290
296
const data = node . value
291
297
292
298
/** @type {CommentToken } */
@@ -311,12 +317,12 @@ function comment(node, state) {
311
317
* hast raw node.
312
318
* @param {State } state
313
319
* Info passed around about the current state.
314
- * @returns {void }
320
+ * @returns {undefined }
315
321
* Nothing.
316
322
*/
317
323
function handleRaw ( node , state ) {
318
324
// Reset preprocessor:
319
- // See: <https://github.com/inikulin/parse5/blob/8e22fe4 /packages/parse5/lib/tokenizer/preprocessor.ts#L18-L31>.
325
+ // See: <https://github.com/inikulin/parse5/blob/6f7ca60 /packages/parse5/lib/tokenizer/preprocessor.ts#L18-L31>.
320
326
state . parser . tokenizer . preprocessor . html = ''
321
327
// @ts -expect-error: private.
322
328
// type-coverage:ignore-next-line
@@ -353,6 +359,8 @@ function handleRaw(node, state) {
353
359
354
360
// Note: `State` is not exposed by `parse5`, so these numbers are fragile.
355
361
// See: <https://github.com/inikulin/parse5/blob/46cba43/packages/parse5/lib/tokenizer/index.ts#L58>
362
+ // Note: a change to `parse5`, which breaks this, was merged but not released.
363
+ // Investigate when it is.
356
364
if (
357
365
state . parser . tokenizer . state === 72 /* NAMED_CHARACTER_REFERENCE */ ||
358
366
state . parser . tokenizer . state === 78 /* NUMERIC_CHARACTER_REFERENCE_END */
@@ -377,7 +385,7 @@ function handleRaw(node, state) {
377
385
* unknown node.
378
386
* @param {State } state
379
387
* Info passed around about the current state.
380
- * @returns {void }
388
+ * @returns {undefined }
381
389
* Never.
382
390
*/
383
391
function unknown ( node_ , state ) {
@@ -407,7 +415,7 @@ function unknown(node_, state) {
407
415
* Info passed around about the current state.
408
416
* @param {Point | undefined } point
409
417
* Point.
410
- * @returns {void }
418
+ * @returns {undefined }
411
419
* Nothing.
412
420
*/
413
421
function resetTokenizer ( state , point ) {
@@ -480,7 +488,7 @@ function resetTokenizer(state, point) {
480
488
* Info passed around about the current state.
481
489
* @param {Point | undefined } point
482
490
* Point.
483
- * @returns {void }
491
+ * @returns {undefined }
484
492
* Nothing.
485
493
*/
486
494
function setPoint ( state , point ) {
@@ -513,7 +521,7 @@ function setPoint(state, point) {
513
521
* Element.
514
522
* @param {State } state
515
523
* Info passed around about the current state.
516
- * @returns {void }
524
+ * @returns {undefined }
517
525
* Nothing.
518
526
*/
519
527
function startTag ( node , state ) {
@@ -578,7 +586,7 @@ function startTag(node, state) {
578
586
* Element.
579
587
* @param {State } state
580
588
* Info passed around about the current state.
581
- * @returns {void }
589
+ * @returns {undefined }
582
590
* Nothing.
583
591
*/
584
592
function endTag ( node , state ) {
@@ -663,23 +671,30 @@ function documentMode(node) {
663
671
* `parse5` location.
664
672
*/
665
673
function createParse5Location ( node ) {
666
- const start = pointStart ( node )
667
- const end = pointEnd ( node )
668
-
669
- return {
670
- // @ts -expect-error: could be `undefined` in hast, which `parse5` types don’t want.
671
- startLine : start ?. line ,
672
- // @ts -expect-error: could be `undefined` in hast, which `parse5` types don’t want.
673
- startCol : start ?. column ,
674
- // @ts -expect-error: could be `undefined` in hast, which `parse5` types don’t want.
675
- startOffset : start ?. offset ,
676
- // @ts -expect-error: could be `undefined` in hast, which `parse5` types don’t want.
677
- endLine : end ?. line ,
678
- // @ts -expect-error: could be `undefined` in hast, which `parse5` types don’t want.
679
- endCol : end ?. column ,
680
- // @ts -expect-error: could be `undefined` in hast, which `parse5` types don’t want.
681
- endOffset : end ?. offset
674
+ const start = pointStart ( node ) || {
675
+ line : undefined ,
676
+ column : undefined ,
677
+ offset : undefined
678
+ }
679
+ const end = pointEnd ( node ) || {
680
+ line : undefined ,
681
+ column : undefined ,
682
+ offset : undefined
682
683
}
684
+
685
+ /** @type {Record<keyof Location, number | undefined> } */
686
+ const location = {
687
+ startLine : start . line ,
688
+ startCol : start . column ,
689
+ startOffset : start . offset ,
690
+ endLine : end . line ,
691
+ endCol : end . column ,
692
+ endOffset : end . offset
693
+ }
694
+
695
+ // @ts -expect-error: unist point values can be `undefined` in hast, which
696
+ // `parse5` types don’t want.
697
+ return location
683
698
}
684
699
685
700
/**
0 commit comments