1
1
/**
2
- * @typedef {import('estree-jsx').Node } Node
3
2
* @typedef {import('estree-jsx').Program } Program
4
- * @typedef {import('estree-jsx').JSXAttribute } JSXAttribute
5
- * @typedef {import('estree-jsx').JSXClosingElement } JSXClosingElement
6
- * @typedef {import('estree-jsx').JSXClosingFragment } JSXClosingFragment
7
- * @typedef {import('estree-jsx').JSXElement } JSXElement
8
- * @typedef {import('estree-jsx').JSXEmptyExpression } JSXEmptyExpression
9
- * @typedef {import('estree-jsx').JSXExpressionContainer } JSXExpressionContainer
10
- * @typedef {import('estree-jsx').JSXFragment } JSXFragment
11
- * @typedef {import('estree-jsx').JSXIdentifier } JSXIdentifier
12
- * @typedef {import('estree-jsx').JSXMemberExpression } JSXMemberExpression
13
- * @typedef {import('estree-jsx').JSXNamespacedName } JSXNamespacedName
14
- * @typedef {import('estree-jsx').JSXOpeningElement } JSXOpeningElement
15
- * @typedef {import('estree-jsx').JSXOpeningFragment } JSXOpeningFragment
16
- * @typedef {import('estree-jsx').JSXSpreadAttribute } JSXSpreadAttribute
17
- * @typedef {import('estree-jsx').JSXText } JSXText
18
- * @typedef {import('vfile').VFile } VFile
19
3
* @typedef {typeof import('source-map').SourceMapGenerator } SourceMapGenerator
20
4
*
21
- * @typedef {Omit<import('astring').State, 'write'> & {write: ((code: string, node?: Node) => void)} } State
22
- *
23
- * @typedef {{[K in Node['type']]: (node: Node, state: State) => void} } Generator
24
- *
25
5
* @typedef RecmaStringifyOptions
26
6
* @property {SourceMapGenerator } [SourceMapGenerator]
27
7
* Generate a source map by passing a `SourceMapGenerator` from `source-map`
28
8
* in.
29
9
*/
30
10
31
- import { GENERATOR , generate } from 'astring '
11
+ import { toJs , jsx } from 'estree-util-to-js '
32
12
33
13
/**
34
14
* A plugin that adds an esast compiler: a small wrapper around `astring` to add
@@ -43,304 +23,16 @@ export function recmaStringify(options = {}) {
43
23
44
24
/** @type {import('unified').CompilerFunction<Program, string> } */
45
25
function compiler ( tree , file ) {
46
- /** @type {InstanceType<SourceMapGenerator>|undefined } */
47
- let sourceMap
48
-
49
- if ( SourceMapGenerator ) {
50
- sourceMap = new SourceMapGenerator ( { file : file . path || 'unknown.mdx' } )
51
- }
52
-
53
- const generator = {
54
- ...GENERATOR ,
55
- JSXAttribute,
56
- JSXClosingElement,
57
- JSXClosingFragment,
58
- JSXElement,
59
- JSXEmptyExpression,
60
- JSXExpressionContainer,
61
- JSXFragment,
62
- JSXIdentifier,
63
- JSXMemberExpression,
64
- JSXNamespacedName,
65
- JSXOpeningElement,
66
- JSXOpeningFragment,
67
- JSXSpreadAttribute,
68
- JSXText
69
- }
70
-
71
- const result = generate ( tree , {
72
- generator,
73
- comments : true ,
74
- sourceMap
75
- } )
76
-
77
- if ( sourceMap ) {
78
- file . map = sourceMap . toJSON ( )
79
- }
80
-
81
- return result
82
- }
83
- }
84
-
85
- /**
86
- * `attr`
87
- * `attr="something"`
88
- * `attr={1}`
89
- *
90
- * @this {Generator}
91
- * @param {JSXAttribute } node
92
- * @param {State } state
93
- * @returns {void }
94
- */
95
- function JSXAttribute ( node , state ) {
96
- this [ node . name . type ] ( node . name , state )
97
-
98
- if ( node . value !== undefined && node . value !== null ) {
99
- state . write ( '=' )
100
-
101
- // Encode double quotes in attribute values.
102
- if ( node . value . type === 'Literal' ) {
103
- state . write (
104
- '"' + encodeJsx ( String ( node . value . value ) ) . replace ( / " / g, '"' ) + '"' ,
105
- node
106
- )
107
- } else {
108
- this [ node . value . type ] ( node . value , state )
109
- }
110
- }
111
- }
112
-
113
- /**
114
- * `</div>`
115
- *
116
- * @this {Generator}
117
- * @param {JSXClosingElement } node
118
- * @param {State } state
119
- * @returns {void }
120
- */
121
- function JSXClosingElement ( node , state ) {
122
- state . write ( '</' )
123
- this [ node . name . type ] ( node . name , state )
124
- state . write ( '>' )
125
- }
126
-
127
- /**
128
- * `</>`
129
- *
130
- * @this {Generator}
131
- * @param {JSXClosingFragment } node
132
- * @param {State } state
133
- * @returns {void }
134
- */
135
- function JSXClosingFragment ( node , state ) {
136
- state . write ( '</>' , node )
137
- }
138
-
139
- /**
140
- * `<div />`
141
- * `<div></div>`
142
- *
143
- * @this {Generator}
144
- * @param {JSXElement } node
145
- * @param {State } state
146
- * @returns {void }
147
- */
148
- function JSXElement ( node , state ) {
149
- let index = - 1
150
-
151
- this [ node . openingElement . type ] ( node . openingElement , state )
26
+ const result = SourceMapGenerator
27
+ ? toJs ( tree , {
28
+ filePath : file . path || 'unknown.mdx' ,
29
+ SourceMapGenerator,
30
+ handlers : jsx
31
+ } )
32
+ : toJs ( tree , { handlers : jsx } )
152
33
153
- if ( node . children ) {
154
- while ( ++ index < node . children . length ) {
155
- const child = node . children [ index ]
34
+ file . map = result . map
156
35
157
- // Supported in types but not by Acorn.
158
- /* c8 ignore next 3 */
159
- if ( child . type === 'JSXSpreadChild' ) {
160
- throw new Error ( 'JSX spread children are not supported' )
161
- }
162
-
163
- this [ child . type ] ( child , state )
164
- }
165
- }
166
-
167
- if ( node . closingElement ) {
168
- this [ node . closingElement . type ] ( node . closingElement , state )
36
+ return result . value
169
37
}
170
38
}
171
-
172
- /**
173
- * `{}` (always in a `JSXExpressionContainer`, which does the curlies)
174
- *
175
- * @this {Generator}
176
- * @returns {void }
177
- */
178
- function JSXEmptyExpression ( ) { }
179
-
180
- /**
181
- * `{expression}`
182
- *
183
- * @this {Generator}
184
- * @param {JSXExpressionContainer } node
185
- * @param {State } state
186
- * @returns {void }
187
- */
188
- function JSXExpressionContainer ( node , state ) {
189
- state . write ( '{' )
190
- this [ node . expression . type ] ( node . expression , state )
191
- state . write ( '}' )
192
- }
193
-
194
- /**
195
- * `<></>`
196
- *
197
- * @this {Generator}
198
- * @param {JSXFragment } node
199
- * @param {State } state
200
- * @returns {void }
201
- */
202
- function JSXFragment ( node , state ) {
203
- let index = - 1
204
-
205
- this [ node . openingFragment . type ] ( node . openingFragment , state )
206
-
207
- if ( node . children ) {
208
- while ( ++ index < node . children . length ) {
209
- const child = node . children [ index ]
210
-
211
- // Supported in types but not by Acorn.
212
- /* c8 ignore next 3 */
213
- if ( child . type === 'JSXSpreadChild' ) {
214
- throw new Error ( 'JSX spread children are not supported' )
215
- }
216
-
217
- this [ child . type ] ( child , state )
218
- }
219
- }
220
-
221
- this [ node . closingFragment . type ] ( node . closingFragment , state )
222
- }
223
-
224
- /**
225
- * `div`
226
- *
227
- * @this {Generator}
228
- * @param {JSXIdentifier } node
229
- * @param {State } state
230
- * @returns {void }
231
- */
232
- function JSXIdentifier ( node , state ) {
233
- state . write ( node . name , node )
234
- }
235
-
236
- /**
237
- * `member.expression`
238
- *
239
- * @this {Generator}
240
- * @param {JSXMemberExpression } node
241
- * @param {State } state
242
- * @returns {void }
243
- */
244
- function JSXMemberExpression ( node , state ) {
245
- this [ node . object . type ] ( node . object , state )
246
- state . write ( '.' )
247
- this [ node . property . type ] ( node . property , state )
248
- }
249
-
250
- /**
251
- * `ns:name`
252
- *
253
- * @this {Generator}
254
- * @param {JSXNamespacedName } node
255
- * @param {State } state
256
- * @returns {void }
257
- */
258
- function JSXNamespacedName ( node , state ) {
259
- this [ node . namespace . type ] ( node . namespace , state )
260
- state . write ( ':' )
261
- this [ node . name . type ] ( node . name , state )
262
- }
263
-
264
- /**
265
- * `<div>`
266
- *
267
- * @this {Generator}
268
- * @param {JSXOpeningElement } node
269
- * @param {State } state
270
- * @returns {void }
271
- */
272
- function JSXOpeningElement ( node , state ) {
273
- let index = - 1
274
-
275
- state . write ( '<' )
276
- this [ node . name . type ] ( node . name , state )
277
-
278
- if ( node . attributes ) {
279
- while ( ++ index < node . attributes . length ) {
280
- state . write ( ' ' )
281
- this [ node . attributes [ index ] . type ] ( node . attributes [ index ] , state )
282
- }
283
- }
284
-
285
- state . write ( node . selfClosing ? ' />' : '>' )
286
- }
287
-
288
- /**
289
- * `<>`
290
- *
291
- * @this {Generator}
292
- * @param {JSXOpeningFragment } node
293
- * @param {State } state
294
- * @returns {void }
295
- */
296
- function JSXOpeningFragment ( node , state ) {
297
- state . write ( '<>' , node )
298
- }
299
-
300
- /**
301
- * `{...argument}`
302
- *
303
- * @this {Generator}
304
- * @param {JSXSpreadAttribute } node
305
- * @param {State } state
306
- * @returns {void }
307
- */
308
- function JSXSpreadAttribute ( node , state ) {
309
- state . write ( '{' )
310
- // eslint-disable-next-line new-cap
311
- this . SpreadElement ( node , state )
312
- state . write ( '}' )
313
- }
314
-
315
- /**
316
- * `!`
317
- *
318
- * @this {Generator}
319
- * @param {JSXText } node
320
- * @param {State } state
321
- * @returns {void }
322
- */
323
- function JSXText ( node , state ) {
324
- state . write (
325
- encodeJsx ( node . value ) . replace ( / < | { / g, ( $0 ) =>
326
- $0 === '<' ? '<' : '{'
327
- ) ,
328
- node
329
- )
330
- }
331
-
332
- /**
333
- * Make sure that character references don’t pop up.
334
- * For example, the text `©` should stay that way, and not turn into `©`.
335
- * We could encode all `&` (easy but verbose) or look for actual valid
336
- * references (complex but cleanest output).
337
- * Looking for the 2nd character gives us a middle ground.
338
- * The `#` is for (decimal and hexadecimal) numeric references, the letters
339
- * are for the named references.
340
- *
341
- * @param {string } value
342
- * @returns {string }
343
- */
344
- function encodeJsx ( value ) {
345
- return value . replace ( / & (? = [ # a - z ] ) / gi, '&' )
346
- }
1 commit comments
vercel[bot] commentedon Jul 24, 2022
Successfully deployed to the following URLs:
mdx – ./
mdx-mdx.vercel.app
mdxjs.com
mdx-git-main-mdx.vercel.app
v2.mdxjs.com