11/**
22 * @typedef {import('mdast').Literal } Literal
33 * @typedef {import('mdast-util-from-markdown').Extension } FromMarkdownExtension
4+ * @typedef {import('mdast-util-from-markdown').CompileContext } CompileContext
45 * @typedef {import('mdast-util-from-markdown').Handle } FromMarkdownHandle
5- * @typedef {import('mdast-util-to-markdown/lib/types.js').Options } ToMarkdownExtension
6- * @typedef {import('mdast-util-to-markdown/lib/types.js').Handle } ToMarkdownHandle
7- * @typedef {import('mdast-util-to-markdown/lib/util/indent-lines.js').Map } Map
6+ * @typedef {import('mdast-util-to-markdown').Options } ToMarkdownExtension
87 *
98 * @typedef {import('micromark-extension-frontmatter/matters.js').Options } Options
109 * @typedef {import('micromark-extension-frontmatter/matters.js').Matter } Matter
1413import { matters } from 'micromark-extension-frontmatter/matters.js'
1514
1615/**
17- * Function that can be called to get an extension for
18- * `mdast-util-from-markdown`.
16+ * Create an extension for `mdast-util-from-markdown`.
1917 *
20- * @param {Options } [options]
18+ * @param {Options | null | undefined } [options]
19+ * Configuration.
2120 * @returns {FromMarkdownExtension }
21+ * Extension for `mdast-util-from-markdown`.
2222 */
2323export function frontmatterFromMarkdown ( options ) {
24+ // @ts -expect-error: `micromark-extension-frontmatter` should fix types to
25+ // accept `null` as options.
2426 const settings = matters ( options )
2527 /** @type {FromMarkdownExtension['enter'] } */
2628 const enter = { }
@@ -44,55 +46,78 @@ export function frontmatterFromMarkdown(options) {
4446 */
4547function opener ( matter ) {
4648 return open
47- /** @type {FromMarkdownHandle } */
49+
50+ /**
51+ * @this {CompileContext}
52+ * @type {FromMarkdownHandle }
53+ */
4854 function open ( token ) {
4955 // @ts -expect-error: custom.
5056 this . enter ( { type : matter . type , value : '' } , token )
5157 this . buffer ( )
5258 }
5359}
5460
55- /** @type {FromMarkdownHandle } */
61+ /**
62+ * @this {CompileContext}
63+ * @type {FromMarkdownHandle }
64+ */
5665function close ( token ) {
5766 const data = this . resume ( )
5867 const node = /** @type {Literal } */ ( this . exit ( token ) )
5968 // Remove the initial and final eol.
6069 node . value = data . replace ( / ^ ( \r ? \n | \r ) | ( \r ? \n | \r ) $ / g, '' )
6170}
6271
63- /** @type {FromMarkdownHandle } */
72+ /**
73+ * @this {CompileContext}
74+ * @type {FromMarkdownHandle }
75+ */
6476function value ( token ) {
6577 this . config . enter . data . call ( this , token )
6678 this . config . exit . data . call ( this , token )
6779}
6880
6981/**
70- * Function that can be called to get an extension for
71- * `mdast-util-to-markdown`.
82+ * Create an extension for `mdast-util-to-markdown`.
7283 *
73- * @param {Options } [options]
84+ * @param {Options | null | undefined } [options]
85+ * Configuration.
7486 * @returns {ToMarkdownExtension }
87+ * Extension for `mdast-util-to-markdown`.
7588 */
7689export function frontmatterToMarkdown ( options ) {
90+ // To do: use an extension object with `satisfies` later.
7791 /** @type {ToMarkdownExtension['unsafe'] } */
7892 const unsafe = [ ]
7993 /** @type {ToMarkdownExtension['handlers'] } */
8094 const handlers = { }
95+ // @ts -expect-error: `micromark-extension-frontmatter` should fix types to
96+ // accept `null` as options.
8197 const settings = matters ( options )
8298 let index = - 1
8399
84100 while ( ++ index < settings . length ) {
85101 const matter = settings [ index ]
102+
103+ // @ts -expect-error: this can add custom frontmatter nodes.
104+ // Typing those is the responsibility of the end user.
86105 handlers [ matter . type ] = handler ( matter )
106+
107+ // To do: idea: perhaps make this smarter, with an `after` of the second char?
87108 unsafe . push ( { atBreak : true , character : fence ( matter , 'open' ) . charAt ( 0 ) } )
88109 }
89110
90111 return { unsafe, handlers}
91112}
92113
93114/**
115+ * Create a handle that can serialize a frontmatter node as markdown.
116+ *
94117 * @param {Matter } matter
118+ * Structure.
95119 * @returns {(node: Literal) => string } enter
120+ * Handler.
96121 */
97122function handler ( matter ) {
98123 const open = fence ( matter , 'open' )
@@ -101,18 +126,27 @@ function handler(matter) {
101126 return handle
102127
103128 /**
104- * @type {ToMarkdownHandle }
129+ * Serialize a frontmatter node as markdown.
130+ *
105131 * @param {Literal } node
132+ * Node to serialize.
133+ * @returns {string }
134+ * Serialized node.
106135 */
107136 function handle ( node ) {
108137 return open + ( node . value ? '\n' + node . value : '' ) + '\n' + close
109138 }
110139}
111140
112141/**
142+ * Get an `open` or `close` fence.
143+ *
113144 * @param {Matter } matter
114- * @param {'open'|'close' } prop
145+ * Structure.
146+ * @param {'open' | 'close' } prop
147+ * Field to get.
115148 * @returns {string }
149+ * Fence.
116150 */
117151function fence ( matter , prop ) {
118152 return matter . marker
@@ -122,9 +156,15 @@ function fence(matter, prop) {
122156}
123157
124158/**
125- * @param {Info|string } schema
126- * @param {'open'|'close' } prop
159+ * Take `open` or `close` fields when schema is an info object, or use the
160+ * given value when it is a string.
161+ *
162+ * @param {Info | string } schema
163+ * Info object or value.
164+ * @param {'open' | 'close' } prop
165+ * Field to get.
127166 * @returns {string }
167+ * Thing to use for the opening or closing.
128168 */
129169function pick ( schema , prop ) {
130170 return typeof schema === 'string' ? schema : schema [ prop ]
0 commit comments