1
1
/**
2
- * @typedef {import('mdast').Root|import('mdast').Content } Node
3
- * @typedef {Extract<Node, import('mdast').Parent> } Parent
2
+ * @typedef {import('mdast').Parent } MdastParent
3
+ * @typedef {import('mdast').Content } Content
4
+ * @typedef {import('mdast').Root } Root
5
+ */
6
+
7
+ /**
8
+ * @typedef {Root | Content } Node
9
+ * @typedef {Extract<Node, MdastParent> } Parent
4
10
*
5
11
* @typedef ZoneInfo
6
12
* Extra info.
7
13
* @property {Parent } parent
8
- * Parent of the range .
14
+ * Parent of the section .
9
15
* @property {number } start
10
- * Index of `start` in `parent`
16
+ * Index of `start` in `parent`.
11
17
* @property {number } end
12
- * Index of `end` in `parent`
18
+ * Index of `end` in `parent`.
13
19
*
14
20
* @callback Handler
15
- * Callback called when a range is found.
21
+ * Callback called when a section is found.
16
22
* @param {Node } start
17
- * Start of range .
23
+ * Start of section .
18
24
* @param {Array<Node> } between
19
25
* Nodes between `start` and `end`.
20
26
* @param {Node } end
21
- * End of range .
27
+ * End of section .
22
28
* @param {ZoneInfo } info
23
29
* Extra info.
24
- * @returns {Array<Node>|null|undefined|void }
25
- * Nodes to replace.
30
+ * @returns {Array<Node | null | undefined> | null | undefined | void }
31
+ * Results.
32
+ *
33
+ * If nothing is returned, nothing will be changed.
34
+ * If an array of nodes (can include `null` and `undefined`) is returned, the
35
+ * original section will be replaced by those nodes.
26
36
*/
27
37
28
38
import { commentMarker } from 'mdast-comment-marker'
@@ -37,59 +47,64 @@ import {visit} from 'unist-util-visit'
37
47
* Callback called when a range is found.
38
48
*/
39
49
export function zone ( node , name , callback ) {
40
- /** @type {number| undefined } */
50
+ /** @type {number | undefined } */
41
51
let level
42
- /** @type {Node| undefined } */
52
+ /** @type {Node | undefined } */
43
53
let marker
44
- /** @type {Parent| undefined } */
54
+ /** @type {Parent | undefined } */
45
55
let scope
46
56
47
- visit (
48
- node ,
49
- /**
50
- * Gather one dimensional zones.
51
- */
52
- ( node , index , parent ) => {
53
- const info = commentMarker ( node )
54
- const match =
55
- info && info . name === name && info . attributes . match ( / ( s t a r t | e n d ) \b / )
56
- const type = match && match [ 0 ]
57
+ visit ( node , ( node , index , parent ) => {
58
+ const info = commentMarker ( node )
59
+ const match =
60
+ info && info . name === name ? info . attributes . match ( / ( s t a r t | e n d ) \b / ) : null
61
+ const type = match ? match [ 0 ] : undefined
57
62
58
- if ( parent && index !== null && type ) {
59
- if ( ! scope && type === 'start' ) {
60
- level = 0
61
- marker = node
62
- scope = /** @type {Parent } */ ( parent )
63
+ if ( parent && index !== null && type ) {
64
+ if ( ! scope && type === 'start' ) {
65
+ level = 0
66
+ marker = node
67
+ scope = parent
68
+ }
69
+
70
+ if ( typeof level === 'number' && marker && scope && parent === scope ) {
71
+ if ( type === 'start' ) {
72
+ level ++
73
+ } else {
74
+ level --
63
75
}
64
76
65
- if ( typeof level === 'number' && marker && scope && parent === scope ) {
66
- if ( type === 'start' ) {
67
- level ++
68
- } else {
69
- level --
70
- }
77
+ if ( type === 'end' && ! level ) {
78
+ // @ts -expect-error: Assume `scope` is a valid parent of `node`.
79
+ const start = scope . children . indexOf ( marker )
71
80
72
- if ( type === 'end' && ! level ) {
73
- // @ts -expect-error: Assume `scope` is a valid parent of `node`.
74
- const start = scope . children . indexOf ( marker )
81
+ const nodes = callback (
82
+ marker ,
83
+ scope . children . slice ( start + 1 , index ) ,
84
+ node ,
85
+ { start, end : index , parent : scope }
86
+ )
75
87
76
- const result = callback (
77
- marker ,
78
- scope . children . slice ( start + 1 , index ) ,
79
- node ,
80
- { start , end : index , parent : scope }
81
- )
88
+ if ( nodes ) {
89
+ // Ensure no empty nodes are inserted.
90
+ // This could be the case if `end` is in `nodes` but no `end` node exists.
91
+ /** @type { Array<Node> } */
92
+ const result = [ ]
93
+ let offset = - 1
82
94
83
- if ( result ) {
84
- // @ts -expect-error: Assume the correct children are passed.
85
- scope . children . splice ( start , index - start + 1 , ... result )
95
+ while ( ++ offset < nodes . length ) {
96
+ const node = nodes [ offset ]
97
+ if ( node ) result . push ( node )
86
98
}
87
99
88
- marker = undefined
89
- scope = undefined
100
+ // @ts -expect-error: Assume the correct children are passed.
101
+ scope . children . splice ( start , index - start + 1 , ... result )
90
102
}
103
+
104
+ marker = undefined
105
+ scope = undefined
91
106
}
92
107
}
93
108
}
94
- )
109
+ } )
95
110
}
0 commit comments