1+ /**
2+ * @typedef {import('mdast-util-from-markdown').Handle } FromMarkdownHandle
3+ * @typedef {import('mdast-util-from-markdown').Extension } FromMarkdownExtension
4+ * @typedef {import('mdast-util-to-markdown/lib/types.js').Node } Node
5+ * @typedef {import('mdast-util-to-markdown/lib/types.js').Parent } Parent
6+ * @typedef {import('mdast-util-to-markdown/lib/types.js').Handle } ToMarkdownHandle
7+ * @typedef {import('mdast-util-to-markdown/lib/types.js').Context } Context
8+ * @typedef {import('mdast-util-to-markdown/lib/types.js').Options } ToMarkdownExtension
9+ *
10+ * @typedef {Record<string, string> } Attributes
11+ * @typedef {{name: string, attributes?: Attributes} } Directive
12+ *
13+ * @typedef {Parent & Directive & {type: 'textDirective', children: Array.<import('mdast').PhrasingContent>} } TextDirective
14+ * @typedef {Parent & Directive & {type: 'leafDirective', children: Array.<import('mdast').PhrasingContent>} } LeafDirective
15+ * @typedef {Parent & Directive & {type: 'containerDirective', children: Array.<import('mdast').BlockContent>} } ContainerDirective
16+ */
17+
118import { decodeEntity } from 'parse-entities/decode-entity.js'
219import { stringifyEntitiesLight } from 'stringify-entities'
320import { visitParents } from 'unist-util-visit-parents'
@@ -11,6 +28,7 @@ const shortcut = /^[^\t\n\r "#'.<=>`}]+$/
1128
1229handleDirective . peek = peekDirective
1330
31+ /** @type {FromMarkdownExtension } */
1432export const directiveFromMarkdown = {
1533 canContainEols : [ 'textDirective' ] ,
1634 enter : {
@@ -52,6 +70,7 @@ export const directiveFromMarkdown = {
5270 }
5371}
5472
73+ /** @type {ToMarkdownExtension } */
5574export const directiveToMarkdown = {
5675 unsafe : [
5776 {
@@ -77,74 +96,104 @@ export const directiveToMarkdown = {
7796 }
7897}
7998
99+ /** @type {FromMarkdownHandle } */
80100function enterContainer ( token ) {
81101 enter . call ( this , 'containerDirective' , token )
82102}
83103
104+ /** @type {FromMarkdownHandle } */
84105function enterLeaf ( token ) {
85106 enter . call ( this , 'leafDirective' , token )
86107}
87108
109+ /** @type {FromMarkdownHandle } */
88110function enterText ( token ) {
89111 enter . call ( this , 'textDirective' , token )
90112}
91113
114+ /**
115+ * @this {ThisParameterType<FromMarkdownHandle>}
116+ * @param {string } type
117+ * @param {Parameters<FromMarkdownHandle>[0] } token
118+ */
92119function enter ( type , token ) {
120+ // @ts -expect-error: custom node.
93121 this . enter ( { type, name : '' , attributes : { } , children : [ ] } , token )
94122}
95123
124+ /**
125+ * @this {ThisParameterType<FromMarkdownHandle>}
126+ * @param {Parameters<FromMarkdownHandle>[0] } token
127+ */
96128function exitName ( token ) {
97129 this . stack [ this . stack . length - 1 ] . name = this . sliceSerialize ( token )
98130}
99131
132+ /** @type {FromMarkdownHandle } */
100133function enterContainerLabel ( token ) {
101134 this . enter (
102135 { type : 'paragraph' , data : { directiveLabel : true } , children : [ ] } ,
103136 token
104137 )
105138}
106139
140+ /** @type {FromMarkdownHandle } */
107141function exitContainerLabel ( token ) {
108142 this . exit ( token )
109143}
110144
145+ /** @type {FromMarkdownHandle } */
111146function enterAttributes ( ) {
112147 this . setData ( 'directiveAttributes' , [ ] )
113148 this . buffer ( ) // Capture EOLs
114149}
115150
151+ /** @type {FromMarkdownHandle } */
116152function exitAttributeIdValue ( token ) {
117- this . getData ( 'directiveAttributes' ) . push ( [
118- 'id' ,
119- decodeLight ( this . sliceSerialize ( token ) )
120- ] )
153+ /** @type { Array.<[string, string]> } */
154+ // @ts -expect-error: custom.
155+ const list = this . getData ( 'directiveAttributes' )
156+ list . push ( [ 'id' , decodeLight ( this . sliceSerialize ( token ) ) ] )
121157}
122158
159+ /** @type {FromMarkdownHandle } */
123160function exitAttributeClassValue ( token ) {
124- this . getData ( 'directiveAttributes' ) . push ( [
125- 'class' ,
126- decodeLight ( this . sliceSerialize ( token ) )
127- ] )
161+ /** @type { Array.<[string, string]> } */
162+ // @ts -expect-error: custom.
163+ const list = this . getData ( 'directiveAttributes' )
164+ list . push ( [ 'class' , decodeLight ( this . sliceSerialize ( token ) ) ] )
128165}
129166
167+ /** @type {FromMarkdownHandle } */
130168function exitAttributeValue ( token ) {
131- const attributes = this . getData ( 'directiveAttributes' )
132- attributes [ attributes . length - 1 ] [ 1 ] = decodeLight ( this . sliceSerialize ( token ) )
169+ /** @type {Array.<[string, string]> } */
170+ // @ts -expect-error: custom.
171+ const list = this . getData ( 'directiveAttributes' )
172+ list [ list . length - 1 ] [ 1 ] = decodeLight ( this . sliceSerialize ( token ) )
133173}
134174
175+ /** @type {FromMarkdownHandle } */
135176function exitAttributeName ( token ) {
177+ /** @type {Array.<[string, string]> } */
178+ // @ts -expect-error: custom.
179+ const list = this . getData ( 'directiveAttributes' )
180+
136181 // Attribute names in CommonMark are significantly limited, so character
137182 // references can’t exist.
138- this . getData ( 'directiveAttributes' ) . push ( [ this . sliceSerialize ( token ) , '' ] )
183+ list . push ( [ this . sliceSerialize ( token ) , '' ] )
139184}
140185
186+ /** @type {FromMarkdownHandle } */
141187function exitAttributes ( ) {
142- const attributes = this . getData ( 'directiveAttributes' )
188+ /** @type {Array.<[string, string]> } */
189+ // @ts -expect-error: custom.
190+ const list = this . getData ( 'directiveAttributes' )
191+ /** @type {Record.<string, string> } */
143192 const cleaned = { }
144193 let index = - 1
145194
146- while ( ++ index < attributes . length ) {
147- const attribute = attributes [ index ]
195+ while ( ++ index < list . length ) {
196+ const attribute = list [ index ]
148197
149198 if ( attribute [ 0 ] === 'class' && cleaned . class ) {
150199 cleaned . class += ' ' + attribute [ 1 ]
@@ -158,10 +207,15 @@ function exitAttributes() {
158207 this . stack [ this . stack . length - 1 ] . attributes = cleaned
159208}
160209
210+ /** @type {FromMarkdownHandle } */
161211function exit ( token ) {
162212 this . exit ( token )
163213}
164214
215+ /**
216+ * @type {ToMarkdownHandle }
217+ * @param {TextDirective|LeafDirective|ContainerDirective } node
218+ */
165219function handleDirective ( node , _ , context ) {
166220 const prefix = fence ( node )
167221 const exit = context . enter ( node . type )
@@ -181,15 +235,23 @@ function handleDirective(node, _, context) {
181235 return value
182236}
183237
238+ /** @type {ToMarkdownHandle } */
184239function peekDirective ( ) {
185240 return ':'
186241}
187242
243+ /**
244+ * @param {TextDirective|LeafDirective|ContainerDirective } node
245+ * @param {Context } context
246+ * @returns {string }
247+ */
188248function label ( node , context ) {
249+ /** @type {Parent } */
189250 let label = node
190251
191252 if ( node . type === 'containerDirective' ) {
192253 if ( ! inlineDirectiveLabel ( node ) ) return ''
254+ // @ts -expect-error: we just asserted it’s a parent.
193255 label = node . children [ 0 ]
194256 }
195257
@@ -201,14 +263,24 @@ function label(node, context) {
201263 return value ? '[' + value + ']' : ''
202264}
203265
266+ /**
267+ * @param {TextDirective|LeafDirective|ContainerDirective } node
268+ * @param {Context } context
269+ * @returns {string }
270+ */
204271function attributes ( node , context ) {
205272 const quote = checkQuote ( context )
206273 const subset = node . type === 'textDirective' ? [ quote ] : [ quote , '\n' , '\r' ]
207274 const attrs = node . attributes || { }
275+ /** @type {Array.<string> } */
208276 const values = [ ]
277+ /** @type {string|undefined } */
209278 let classesFull
279+ /** @type {string|undefined } */
210280 let classes
281+ /** @type {string|undefined } */
211282 let id
283+ /** @type {string } */
212284 let key
213285
214286 for ( key in attrs ) {
@@ -217,25 +289,29 @@ function attributes(node, context) {
217289 attrs [ key ] !== undefined &&
218290 attrs [ key ] !== null
219291 ) {
220- let value = String ( attrs [ key ] )
292+ const value = String ( attrs [ key ] )
221293
222294 if ( key === 'id' ) {
223295 id = shortcut . test ( value ) ? '#' + value : quoted ( 'id' , value )
224296 } else if ( key === 'class' ) {
225- value = value . split ( / [ \t \n \r ] + / g)
226- classesFull = [ ]
227- classes = [ ]
297+ const list = value . split ( / [ \t \n \r ] + / g)
298+ /** @type {Array.<string> } */
299+ const classesFullList = [ ]
300+ /** @type {Array.<string> } */
301+ const classesList = [ ]
228302 let index = - 1
229303
230- while ( ++ index < value . length ) {
231- ; ( shortcut . test ( value [ index ] ) ? classes : classesFull ) . push (
232- value [ index ]
304+ while ( ++ index < list . length ) {
305+ ; ( shortcut . test ( list [ index ] ) ? classesList : classesFullList ) . push (
306+ list [ index ]
233307 )
234308 }
235309
236310 classesFull =
237- classesFull . length > 0 ? quoted ( 'class' , classesFull . join ( ' ' ) ) : ''
238- classes = classes . length > 0 ? '.' + classes . join ( '.' ) : ''
311+ classesFullList . length > 0
312+ ? quoted ( 'class' , classesFullList . join ( ' ' ) )
313+ : ''
314+ classes = classesList . length > 0 ? '.' + classesList . join ( '.' ) : ''
239315 } else {
240316 values . push ( quoted ( key , value ) )
241317 }
@@ -256,6 +332,11 @@ function attributes(node, context) {
256332
257333 return values . length > 0 ? '{' + values . join ( ' ' ) + '}' : ''
258334
335+ /**
336+ * @param {string } key
337+ * @param {string } value
338+ * @returns {string }
339+ */
259340 function quoted ( key , value ) {
260341 return (
261342 key +
@@ -266,6 +347,11 @@ function attributes(node, context) {
266347 }
267348}
268349
350+ /**
351+ * @param {TextDirective|LeafDirective|ContainerDirective } node
352+ * @param {Context } context
353+ * @returns {string }
354+ */
269355function content ( node , context ) {
270356 return containerFlow (
271357 inlineDirectiveLabel ( node )
@@ -275,26 +361,43 @@ function content(node, context) {
275361 )
276362}
277363
364+ /**
365+ * @param {TextDirective|LeafDirective|ContainerDirective } node
366+ * @returns {boolean }
367+ */
278368function inlineDirectiveLabel ( node ) {
279- return (
369+ return Boolean (
280370 node . children &&
281- node . children [ 0 ] &&
282- node . children [ 0 ] . data &&
283- node . children [ 0 ] . data . directiveLabel
371+ node . children [ 0 ] &&
372+ node . children [ 0 ] . data &&
373+ node . children [ 0 ] . data . directiveLabel
284374 )
285375}
286376
377+ /**
378+ * @param {string } value
379+ * @returns {string }
380+ */
287381function decodeLight ( value ) {
288382 return value . replace (
289383 / & ( # ( \d { 1 , 7 } | x [ \d a - f ] { 1 , 6 } ) | [ \d a - z ] { 1 , 31 } ) ; / gi,
290384 decodeIfPossible
291385 )
292386}
293387
388+ /**
389+ * @param {string } $0
390+ * @param {string } $1
391+ * @returns {string }
392+ */
294393function decodeIfPossible ( $0 , $1 ) {
295394 return decodeEntity ( $1 ) || $0
296395}
297396
397+ /**
398+ * @param {TextDirective|LeafDirective|ContainerDirective } node
399+ * @returns {string }
400+ */
298401function fence ( node ) {
299402 let size = 0
300403
@@ -309,7 +412,8 @@ function fence(node) {
309412
310413 return ':' . repeat ( size )
311414
312- function onvisit ( node , parents ) {
415+ /** @type {import('unist-util-visit-parents').Visitor<TextDirective|LeafDirective|ContainerDirective> } */
416+ function onvisit ( _ , parents ) {
313417 let index = parents . length
314418 let nesting = 0
315419
0 commit comments