11/**
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
410 *
511 * @typedef ZoneInfo
612 * Extra info.
713 * @property {Parent } parent
8- * Parent of the range .
14+ * Parent of the section .
915 * @property {number } start
10- * Index of `start` in `parent`
16+ * Index of `start` in `parent`.
1117 * @property {number } end
12- * Index of `end` in `parent`
18+ * Index of `end` in `parent`.
1319 *
1420 * @callback Handler
15- * Callback called when a range is found.
21+ * Callback called when a section is found.
1622 * @param {Node } start
17- * Start of range .
23+ * Start of section .
1824 * @param {Array<Node> } between
1925 * Nodes between `start` and `end`.
2026 * @param {Node } end
21- * End of range .
27+ * End of section .
2228 * @param {ZoneInfo } info
2329 * 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.
2636 */
2737
2838import { commentMarker } from 'mdast-comment-marker'
@@ -37,59 +47,64 @@ import {visit} from 'unist-util-visit'
3747 * Callback called when a range is found.
3848 */
3949export function zone ( node , name , callback ) {
40- /** @type {number| undefined } */
50+ /** @type {number | undefined } */
4151 let level
42- /** @type {Node| undefined } */
52+ /** @type {Node | undefined } */
4353 let marker
44- /** @type {Parent| undefined } */
54+ /** @type {Parent | undefined } */
4555 let scope
4656
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
5762
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 --
6375 }
6476
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 )
7180
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+ )
7587
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
8294
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 )
8698 }
8799
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 )
90102 }
103+
104+ marker = undefined
105+ scope = undefined
91106 }
92107 }
93108 }
94- )
109+ } )
95110}
0 commit comments