1
1
/**
2
2
* @typedef {import('mdast').Literal } Literal
3
3
* @typedef {import('mdast-util-from-markdown').Extension } FromMarkdownExtension
4
+ * @typedef {import('mdast-util-from-markdown').CompileContext } CompileContext
4
5
* @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
8
7
*
9
8
* @typedef {import('micromark-extension-frontmatter/matters.js').Options } Options
10
9
* @typedef {import('micromark-extension-frontmatter/matters.js').Matter } Matter
14
13
import { matters } from 'micromark-extension-frontmatter/matters.js'
15
14
16
15
/**
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`.
19
17
*
20
- * @param {Options } [options]
18
+ * @param {Options | null | undefined } [options]
19
+ * Configuration.
21
20
* @returns {FromMarkdownExtension }
21
+ * Extension for `mdast-util-from-markdown`.
22
22
*/
23
23
export function frontmatterFromMarkdown ( options ) {
24
+ // @ts -expect-error: `micromark-extension-frontmatter` should fix types to
25
+ // accept `null` as options.
24
26
const settings = matters ( options )
25
27
/** @type {FromMarkdownExtension['enter'] } */
26
28
const enter = { }
@@ -44,55 +46,78 @@ export function frontmatterFromMarkdown(options) {
44
46
*/
45
47
function opener ( matter ) {
46
48
return open
47
- /** @type {FromMarkdownHandle } */
49
+
50
+ /**
51
+ * @this {CompileContext}
52
+ * @type {FromMarkdownHandle }
53
+ */
48
54
function open ( token ) {
49
55
// @ts -expect-error: custom.
50
56
this . enter ( { type : matter . type , value : '' } , token )
51
57
this . buffer ( )
52
58
}
53
59
}
54
60
55
- /** @type {FromMarkdownHandle } */
61
+ /**
62
+ * @this {CompileContext}
63
+ * @type {FromMarkdownHandle }
64
+ */
56
65
function close ( token ) {
57
66
const data = this . resume ( )
58
67
const node = /** @type {Literal } */ ( this . exit ( token ) )
59
68
// Remove the initial and final eol.
60
69
node . value = data . replace ( / ^ ( \r ? \n | \r ) | ( \r ? \n | \r ) $ / g, '' )
61
70
}
62
71
63
- /** @type {FromMarkdownHandle } */
72
+ /**
73
+ * @this {CompileContext}
74
+ * @type {FromMarkdownHandle }
75
+ */
64
76
function value ( token ) {
65
77
this . config . enter . data . call ( this , token )
66
78
this . config . exit . data . call ( this , token )
67
79
}
68
80
69
81
/**
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`.
72
83
*
73
- * @param {Options } [options]
84
+ * @param {Options | null | undefined } [options]
85
+ * Configuration.
74
86
* @returns {ToMarkdownExtension }
87
+ * Extension for `mdast-util-to-markdown`.
75
88
*/
76
89
export function frontmatterToMarkdown ( options ) {
90
+ // To do: use an extension object with `satisfies` later.
77
91
/** @type {ToMarkdownExtension['unsafe'] } */
78
92
const unsafe = [ ]
79
93
/** @type {ToMarkdownExtension['handlers'] } */
80
94
const handlers = { }
95
+ // @ts -expect-error: `micromark-extension-frontmatter` should fix types to
96
+ // accept `null` as options.
81
97
const settings = matters ( options )
82
98
let index = - 1
83
99
84
100
while ( ++ index < settings . length ) {
85
101
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.
86
105
handlers [ matter . type ] = handler ( matter )
106
+
107
+ // To do: idea: perhaps make this smarter, with an `after` of the second char?
87
108
unsafe . push ( { atBreak : true , character : fence ( matter , 'open' ) . charAt ( 0 ) } )
88
109
}
89
110
90
111
return { unsafe, handlers}
91
112
}
92
113
93
114
/**
115
+ * Create a handle that can serialize a frontmatter node as markdown.
116
+ *
94
117
* @param {Matter } matter
118
+ * Structure.
95
119
* @returns {(node: Literal) => string } enter
120
+ * Handler.
96
121
*/
97
122
function handler ( matter ) {
98
123
const open = fence ( matter , 'open' )
@@ -101,18 +126,27 @@ function handler(matter) {
101
126
return handle
102
127
103
128
/**
104
- * @type {ToMarkdownHandle }
129
+ * Serialize a frontmatter node as markdown.
130
+ *
105
131
* @param {Literal } node
132
+ * Node to serialize.
133
+ * @returns {string }
134
+ * Serialized node.
106
135
*/
107
136
function handle ( node ) {
108
137
return open + ( node . value ? '\n' + node . value : '' ) + '\n' + close
109
138
}
110
139
}
111
140
112
141
/**
142
+ * Get an `open` or `close` fence.
143
+ *
113
144
* @param {Matter } matter
114
- * @param {'open'|'close' } prop
145
+ * Structure.
146
+ * @param {'open' | 'close' } prop
147
+ * Field to get.
115
148
* @returns {string }
149
+ * Fence.
116
150
*/
117
151
function fence ( matter , prop ) {
118
152
return matter . marker
@@ -122,9 +156,15 @@ function fence(matter, prop) {
122
156
}
123
157
124
158
/**
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.
127
166
* @returns {string }
167
+ * Thing to use for the opening or closing.
128
168
*/
129
169
function pick ( schema , prop ) {
130
170
return typeof schema === 'string' ? schema : schema [ prop ]
0 commit comments