@orgajs/orgx 2.5.2 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -47,14 +47,14 @@
47
47
  * JSX runtime to use.
48
48
  */
49
49
 
50
+ import { walk } from 'estree-walker'
50
51
  import { analyze } from 'periscopic'
51
- import { stringifyPosition } from 'unist-util-stringify-position'
52
52
  import { positionFromEstree } from 'unist-util-position-from-estree'
53
- import { walk } from 'estree-walker'
53
+ import { stringifyPosition } from 'unist-util-stringify-position'
54
54
  import { create } from '../util/estree-util-create.js'
55
- import { specifiersToDeclarations } from '../util/estree-util-specifiers-to-declarations.js'
56
55
  import { declarationToExpression } from '../util/estree-util-declaration-to-expression.js'
57
56
  import { isDeclaration } from '../util/estree-util-is-declaration.js'
57
+ import { specifiersToDeclarations } from '../util/estree-util-specifiers-to-declarations.js'
58
58
 
59
59
  /**
60
60
  * A plugin to wrap the estree in `OrgContent`.
@@ -62,547 +62,547 @@ import { isDeclaration } from '../util/estree-util-is-declaration.js'
62
62
  * @type {import('unified').Plugin<[RecmaDocumentOptions | null | undefined] | [], Program>}
63
63
  */
64
64
  export function recmaDocument(options) {
65
- // Always given inside `@mdx-js/mdx`
66
- /* c8 ignore next */
67
- const options_ = options || {}
68
- const baseUrl = options_.baseUrl || undefined
69
- const useDynamicImport = options_.useDynamicImport || undefined
70
- const outputFormat = options_.outputFormat || 'program'
71
- const pragma =
72
- options_.pragma === undefined ? 'React.createElement' : options_.pragma
73
- const pragmaFrag =
74
- options_.pragmaFrag === undefined ? 'React.Fragment' : options_.pragmaFrag
75
- const pragmaImportSource = options_.pragmaImportSource || 'react'
76
- const jsxImportSource = options_.jsxImportSource || 'react'
77
- const jsxRuntime = options_.jsxRuntime || 'automatic'
78
-
79
- return (tree, file) => {
80
- /** @type {Array<[string, string] | string>} */
81
- const exportedIdentifiers = []
82
- /** @type {Array<Directive | ModuleDeclaration | Statement>} */
83
- const replacement = []
84
- /** @type {Array<string>} */
85
- const pragmas = []
86
- let exportAllCount = 0
87
- /** @type {ExportDefaultDeclaration | ExportSpecifier | undefined} */
88
- let layout
89
- /** @type {boolean | undefined} */
90
- let content
91
- /** @type {Node} */
92
- let child
93
-
94
- // Patch missing comments, which types say could occur.
95
- /* c8 ignore next */
96
- if (!tree.comments) tree.comments = []
97
-
98
- if (jsxRuntime) {
99
- pragmas.push('@jsxRuntime ' + jsxRuntime)
100
- }
101
-
102
- if (jsxRuntime === 'automatic' && jsxImportSource) {
103
- pragmas.push('@jsxImportSource ' + jsxImportSource)
104
- }
105
-
106
- if (jsxRuntime === 'classic' && pragma) {
107
- pragmas.push('@jsx ' + pragma)
108
- }
109
-
110
- if (jsxRuntime === 'classic' && pragmaFrag) {
111
- pragmas.push('@jsxFrag ' + pragmaFrag)
112
- }
113
-
114
- if (pragmas.length > 0) {
115
- tree.comments.unshift({ type: 'Block', value: pragmas.join(' ') })
116
- }
117
-
118
- if (jsxRuntime === 'classic' && pragmaImportSource) {
119
- if (!pragma) {
120
- throw new Error(
121
- 'Missing `pragma` in classic runtime with `pragmaImportSource`'
122
- )
123
- }
124
-
125
- handleEsm({
126
- type: 'ImportDeclaration',
127
- specifiers: [
128
- {
129
- type: 'ImportDefaultSpecifier',
130
- local: { type: 'Identifier', name: pragma.split('.')[0] },
131
- },
132
- ],
133
- source: { type: 'Literal', value: pragmaImportSource },
134
- })
135
- }
136
-
137
- // Find the `export default`, the JSX expression, and leave the rest
138
- // (import/exports) as they are.
139
- for (child of tree.body) {
140
- // ```js
141
- // export default props => <>{props.children}</>
142
- // ```
143
- //
144
- // Treat it as an inline layout declaration.
145
- if (child.type === 'ExportDefaultDeclaration') {
146
- if (layout) {
147
- file.fail(
148
- 'Cannot specify multiple layouts (previous: ' +
149
- stringifyPosition(positionFromEstree(layout)) +
150
- ')',
151
- positionFromEstree(child),
152
- 'recma-document:duplicate-layout'
153
- )
154
- }
155
-
156
- layout = child
157
- replacement.push({
158
- type: 'VariableDeclaration',
159
- kind: 'const',
160
- declarations: [
161
- {
162
- type: 'VariableDeclarator',
163
- id: { type: 'Identifier', name: 'OrgLayout' },
164
- // @ts-expect-error
165
- init: isDeclaration(child.declaration)
166
- ? declarationToExpression(child.declaration)
167
- : child.declaration,
168
- },
169
- ],
170
- })
171
- }
172
- // ```js
173
- // export {a, b as c} from 'd'
174
- // ```
175
- else if (child.type === 'ExportNamedDeclaration' && child.source) {
176
- const source = /** @type {SimpleLiteral} */ (child.source)
177
-
178
- // Remove `default` or `as default`, but not `default as`, specifier.
179
- child.specifiers = child.specifiers.filter((specifier) => {
180
- // @ts-expect-error
181
- if (specifier.exported.name === 'default') {
182
- if (layout) {
183
- file.fail(
184
- 'Cannot specify multiple layouts (previous: ' +
185
- stringifyPosition(positionFromEstree(layout)) +
186
- ')',
187
- positionFromEstree(child),
188
- 'recma-document:duplicate-layout'
189
- )
190
- }
191
-
192
- layout = specifier
193
-
194
- // Make it just an import: `import OrgLayout from '…'`.
195
- /** @type {Array<ImportDefaultSpecifier | ImportSpecifier>} */
196
- const specifiers = []
197
-
198
- // Default as default / something else as default.
199
- // @ts-expect-error
200
- if (specifier.local.name === 'default') {
201
- specifiers.push({
202
- type: 'ImportDefaultSpecifier',
203
- local: { type: 'Identifier', name: 'OrgLayout' },
204
- })
205
- } else {
206
- /** @type {ImportSpecifier} */
207
- const importSpecifier = {
208
- type: 'ImportSpecifier',
209
- imported: specifier.local,
210
- local: { type: 'Identifier', name: 'OrgLayout' },
211
- }
212
- create(specifier.local, importSpecifier)
213
- specifiers.push(importSpecifier)
214
- }
215
-
216
- /** @type {Literal} */
217
- const from = { type: 'Literal', value: source.value }
218
- create(source, from)
219
-
220
- /** @type {ImportDeclaration} */
221
- const declaration = {
222
- type: 'ImportDeclaration',
223
- specifiers,
224
- source: from,
225
- }
226
- create(specifier, declaration)
227
- handleEsm(declaration)
228
-
229
- return false
230
- }
231
-
232
- return true
233
- })
234
-
235
- // If there are other things imported, keep it.
236
- if (child.specifiers.length > 0) {
237
- handleExport(child)
238
- }
239
- }
240
- // ```js
241
- // export {a, b as c}
242
- // export * from 'a'
243
- // ```
244
- else if (
245
- child.type === 'ExportNamedDeclaration' ||
246
- child.type === 'ExportAllDeclaration'
247
- ) {
248
- handleExport(child)
249
- } else if (child.type === 'ImportDeclaration') {
250
- handleEsm(child)
251
- } else if (
252
- child.type === 'ExpressionStatement' &&
253
- (child.expression.type === 'JSXFragment' ||
254
- child.expression.type === 'JSXElement')
255
- ) {
256
- content = true
257
- replacement.push(...createMdxContent(child.expression, Boolean(layout)))
258
- // The following catch-all branch is because plugins might’ve added
259
- // other things.
260
- // Normally, we only have import/export/jsx, but just add whatever’s
261
- // there.
262
- /* c8 ignore next 3 */
263
- } else {
264
- replacement.push(child)
265
- }
266
- }
267
-
268
- // If there was no JSX content at all, add an empty function.
269
- if (!content) {
270
- replacement.push(...createMdxContent(undefined, Boolean(layout)))
271
- }
272
-
273
- exportedIdentifiers.push(['OrgContent', 'default'])
274
-
275
- if (outputFormat === 'function-body') {
276
- replacement.push({
277
- type: 'ReturnStatement',
278
- argument: {
279
- type: 'ObjectExpression',
280
- properties: [
281
- ...Array.from({ length: exportAllCount }).map(
282
- /**
283
- * @param {undefined} _
284
- * @param {number} index
285
- * @returns {SpreadElement}
286
- */
287
- (_, index) => ({
288
- type: 'SpreadElement',
289
- argument: {
290
- type: 'Identifier',
291
- name: '_exportAll' + (index + 1),
292
- },
293
- })
294
- ),
295
- ...exportedIdentifiers.map((d) => {
296
- /** @type {Property} */
297
- const prop = {
298
- type: 'Property',
299
- kind: 'init',
300
- method: false,
301
- computed: false,
302
- shorthand: typeof d === 'string',
303
- key: {
304
- type: 'Identifier',
305
- name: typeof d === 'string' ? d : d[1],
306
- },
307
- value: {
308
- type: 'Identifier',
309
- name: typeof d === 'string' ? d : d[0],
310
- },
311
- }
312
-
313
- return prop
314
- }),
315
- ],
316
- },
317
- })
318
- } else {
319
- replacement.push({
320
- type: 'ExportDefaultDeclaration',
321
- declaration: { type: 'Identifier', name: 'OrgContent' },
322
- })
323
- }
324
-
325
- tree.body = replacement
326
-
327
- if (baseUrl) {
328
- walk(tree, {
329
- enter(node) {
330
- if (
331
- node.type === 'MemberExpression' &&
332
- 'object' in node &&
333
- node.object.type === 'MetaProperty' &&
334
- node.property.type === 'Identifier' &&
335
- node.object.meta.name === 'import' &&
336
- node.object.property.name === 'meta' &&
337
- node.property.name === 'url'
338
- ) {
339
- /** @type {SimpleLiteral} */
340
- const replacement = { type: 'Literal', value: baseUrl }
341
- this.replace(replacement)
342
- }
343
- },
344
- })
345
- }
346
-
347
- /**
348
- * @param {ExportAllDeclaration | ExportNamedDeclaration} node
349
- * @returns {void}
350
- */
351
- function handleExport(node) {
352
- if (node.type === 'ExportNamedDeclaration') {
353
- // ```js
354
- // export function a() {}
355
- // export class A {}
356
- // export var a = 1
357
- // ```
358
- if (node.declaration) {
359
- exportedIdentifiers.push(
360
- ...analyze(node.declaration).scope.declarations.keys()
361
- )
362
- }
363
-
364
- // ```js
365
- // export {a, b as c}
366
- // export {a, b as c} from 'd'
367
- // ```
368
- for (child of node.specifiers) {
369
- // @ts-expect-error
370
- exportedIdentifiers.push(child.exported.name)
371
- }
372
- }
373
-
374
- handleEsm(node)
375
- }
376
-
377
- /**
378
- * @param {ExportAllDeclaration | ExportNamedDeclaration | ImportDeclaration} node
379
- * @returns {void}
380
- */
381
- function handleEsm(node) {
382
- // Rewrite the source of the `import` / `export … from`.
383
- // See: <https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier>
384
- if (baseUrl && node.source) {
385
- let value = String(node.source.value)
386
-
387
- try {
388
- // A full valid URL.
389
- value = String(new URL(value))
390
- } catch {
391
- // Relative: `/example.js`, `./example.js`, and `../example.js`.
392
- if (/^\.{0,2}\//.test(value)) {
393
- value = String(new URL(value, baseUrl))
394
- }
395
- // Otherwise, it’s a bare specifiers.
396
- // For example `some-package`, `@some-package`, and
397
- // `some-package/path`.
398
- // These are supported in Node and browsers plan to support them
399
- // with import maps (<https://github.com/WICG/import-maps>).
400
- }
401
-
402
- /** @type {Literal} */
403
- const literal = { type: 'Literal', value }
404
- create(node.source, literal)
405
- node.source = literal
406
- }
407
-
408
- /** @type {ModuleDeclaration | Statement | undefined} */
409
- let replace
410
- /** @type {Expression} */
411
- let init
412
-
413
- if (outputFormat === 'function-body') {
414
- if (
415
- // Always have a source:
416
- node.type === 'ImportDeclaration' ||
417
- node.type === 'ExportAllDeclaration' ||
418
- // Source optional:
419
- (node.type === 'ExportNamedDeclaration' && node.source)
420
- ) {
421
- if (!useDynamicImport) {
422
- file.fail(
423
- 'Cannot use `import` or `export … from` in `evaluate` (outputting a function body) by default: please set `useDynamicImport: true` (and probably specify a `baseUrl`)',
424
- positionFromEstree(node),
425
- 'recma-document:invalid-esm-statement'
426
- )
427
- }
428
-
429
- // Just for types.
430
- /* c8 ignore next 3 */
431
- if (!node.source) {
432
- throw new Error('Expected `node.source` to be defined')
433
- }
434
-
435
- // ```
436
- // import 'a'
437
- // //=> await import('a')
438
- // import a from 'b'
439
- // //=> const {default: a} = await import('b')
440
- // export {a, b as c} from 'd'
441
- // //=> const {a, c: b} = await import('d')
442
- // export * from 'a'
443
- // //=> const _exportAll0 = await import('a')
444
- // ```
445
- /** @type {ImportExpression} */
446
- const argument = { type: 'ImportExpression', source: node.source }
447
- create(node, argument)
448
- init = { type: 'AwaitExpression', argument }
449
-
450
- if (
451
- (node.type === 'ImportDeclaration' ||
452
- node.type === 'ExportNamedDeclaration') &&
453
- node.specifiers.length === 0
454
- ) {
455
- replace = { type: 'ExpressionStatement', expression: init }
456
- } else {
457
- replace = {
458
- type: 'VariableDeclaration',
459
- kind: 'const',
460
- declarations:
461
- node.type === 'ExportAllDeclaration'
462
- ? [
463
- {
464
- type: 'VariableDeclarator',
465
- id: {
466
- type: 'Identifier',
467
- name: '_exportAll' + ++exportAllCount,
468
- },
469
- init,
470
- },
471
- ]
472
- : specifiersToDeclarations(node.specifiers, init),
473
- }
474
- }
475
- } else if (node.declaration) {
476
- replace = node.declaration
477
- } else {
478
- /** @type {Array<VariableDeclarator>} */
479
- // @ts-expect-error
480
- const declarators = node.specifiers
481
- .filter(
482
- // @ts-expect-error
483
- (specifier) => specifier.local.name !== specifier.exported.name
484
- )
485
- .map((specifier) => ({
486
- type: 'VariableDeclarator',
487
- id: specifier.exported,
488
- init: specifier.local,
489
- }))
490
-
491
- if (declarators.length > 0) {
492
- replace = {
493
- type: 'VariableDeclaration',
494
- kind: 'const',
495
- declarations: declarators,
496
- }
497
- }
498
- }
499
- } else {
500
- replace = node
501
- }
502
-
503
- if (replace) {
504
- replacement.push(replace)
505
- }
506
- }
507
- }
508
-
509
- /**
510
- * @param {Expression | undefined} [content]
511
- * @param {boolean | undefined} [hasInternalLayout]
512
- * @returns {Array<FunctionDeclaration>}
513
- */
514
- function createMdxContent(content, hasInternalLayout) {
515
- /** @type {JSXElement} */
516
- const element = {
517
- type: 'JSXElement',
518
- openingElement: {
519
- type: 'JSXOpeningElement',
520
- name: { type: 'JSXIdentifier', name: 'OrgLayout' },
521
- attributes: [
522
- {
523
- type: 'JSXSpreadAttribute',
524
- argument: { type: 'Identifier', name: 'props' },
525
- },
526
- ],
527
- selfClosing: false,
528
- },
529
- closingElement: {
530
- type: 'JSXClosingElement',
531
- name: { type: 'JSXIdentifier', name: 'OrgLayout' },
532
- },
533
- children: [
534
- {
535
- type: 'JSXElement',
536
- openingElement: {
537
- type: 'JSXOpeningElement',
538
- name: { type: 'JSXIdentifier', name: '_createOrgContent' },
539
- attributes: [
540
- {
541
- type: 'JSXSpreadAttribute',
542
- argument: { type: 'Identifier', name: 'props' },
543
- },
544
- ],
545
- selfClosing: true,
546
- },
547
- closingElement: null,
548
- children: [],
549
- },
550
- ],
551
- }
552
-
553
- let result = /** @type {Expression} */ (element)
554
-
555
- if (!hasInternalLayout) {
556
- result = {
557
- type: 'ConditionalExpression',
558
- test: { type: 'Identifier', name: 'OrgLayout' },
559
- consequent: result,
560
- alternate: {
561
- type: 'CallExpression',
562
- callee: { type: 'Identifier', name: '_createOrgContent' },
563
- arguments: [{ type: 'Identifier', name: 'props' }],
564
- optional: false,
565
- },
566
- }
567
- }
568
-
569
- let argument = content || { type: 'Literal', value: null }
570
-
571
- // Unwrap a fragment of a single element.
572
- if (
573
- argument &&
574
- argument.type === 'JSXFragment' &&
575
- argument.children.length === 1 &&
576
- argument.children[0].type === 'JSXElement'
577
- ) {
578
- argument = argument.children[0]
579
- }
580
-
581
- return [
582
- {
583
- type: 'FunctionDeclaration',
584
- id: { type: 'Identifier', name: '_createOrgContent' },
585
- params: [{ type: 'Identifier', name: 'props' }],
586
- body: {
587
- type: 'BlockStatement',
588
- body: [{ type: 'ReturnStatement', argument }],
589
- },
590
- },
591
- {
592
- type: 'FunctionDeclaration',
593
- id: { type: 'Identifier', name: 'OrgContent' },
594
- params: [
595
- {
596
- type: 'AssignmentPattern',
597
- left: { type: 'Identifier', name: 'props' },
598
- right: { type: 'ObjectExpression', properties: [] },
599
- },
600
- ],
601
- body: {
602
- type: 'BlockStatement',
603
- body: [{ type: 'ReturnStatement', argument: result }],
604
- },
605
- },
606
- ]
607
- }
65
+ // Always given inside `@mdx-js/mdx`
66
+ /* c8 ignore next */
67
+ const options_ = options || {}
68
+ const baseUrl = options_.baseUrl || undefined
69
+ const useDynamicImport = options_.useDynamicImport || undefined
70
+ const outputFormat = options_.outputFormat || 'program'
71
+ const pragma =
72
+ options_.pragma === undefined ? 'React.createElement' : options_.pragma
73
+ const pragmaFrag =
74
+ options_.pragmaFrag === undefined ? 'React.Fragment' : options_.pragmaFrag
75
+ const pragmaImportSource = options_.pragmaImportSource || 'react'
76
+ const jsxImportSource = options_.jsxImportSource || 'react'
77
+ const jsxRuntime = options_.jsxRuntime || 'automatic'
78
+
79
+ return (tree, file) => {
80
+ /** @type {Array<[string, string] | string>} */
81
+ const exportedIdentifiers = []
82
+ /** @type {Array<Directive | ModuleDeclaration | Statement>} */
83
+ const replacement = []
84
+ /** @type {Array<string>} */
85
+ const pragmas = []
86
+ let exportAllCount = 0
87
+ /** @type {ExportDefaultDeclaration | ExportSpecifier | undefined} */
88
+ let layout
89
+ /** @type {boolean | undefined} */
90
+ let content
91
+ /** @type {Node} */
92
+ let child
93
+
94
+ // Patch missing comments, which types say could occur.
95
+ /* c8 ignore next */
96
+ if (!tree.comments) tree.comments = []
97
+
98
+ if (jsxRuntime) {
99
+ pragmas.push(`@jsxRuntime ${jsxRuntime}`)
100
+ }
101
+
102
+ if (jsxRuntime === 'automatic' && jsxImportSource) {
103
+ pragmas.push(`@jsxImportSource ${jsxImportSource}`)
104
+ }
105
+
106
+ if (jsxRuntime === 'classic' && pragma) {
107
+ pragmas.push(`@jsx ${pragma}`)
108
+ }
109
+
110
+ if (jsxRuntime === 'classic' && pragmaFrag) {
111
+ pragmas.push(`@jsxFrag ${pragmaFrag}`)
112
+ }
113
+
114
+ if (pragmas.length > 0) {
115
+ tree.comments.unshift({ type: 'Block', value: pragmas.join(' ') })
116
+ }
117
+
118
+ if (jsxRuntime === 'classic' && pragmaImportSource) {
119
+ if (!pragma) {
120
+ throw new Error(
121
+ 'Missing `pragma` in classic runtime with `pragmaImportSource`'
122
+ )
123
+ }
124
+
125
+ handleEsm({
126
+ type: 'ImportDeclaration',
127
+ specifiers: [
128
+ {
129
+ type: 'ImportDefaultSpecifier',
130
+ local: { type: 'Identifier', name: pragma.split('.')[0] }
131
+ }
132
+ ],
133
+ source: { type: 'Literal', value: pragmaImportSource }
134
+ })
135
+ }
136
+
137
+ // Find the `export default`, the JSX expression, and leave the rest
138
+ // (import/exports) as they are.
139
+ for (child of tree.body) {
140
+ // ```js
141
+ // export default props => <>{props.children}</>
142
+ // ```
143
+ //
144
+ // Treat it as an inline layout declaration.
145
+ if (child.type === 'ExportDefaultDeclaration') {
146
+ if (layout) {
147
+ file.fail(
148
+ 'Cannot specify multiple layouts (previous: ' +
149
+ stringifyPosition(positionFromEstree(layout)) +
150
+ ')',
151
+ positionFromEstree(child),
152
+ 'recma-document:duplicate-layout'
153
+ )
154
+ }
155
+
156
+ layout = child
157
+ replacement.push({
158
+ type: 'VariableDeclaration',
159
+ kind: 'const',
160
+ declarations: [
161
+ {
162
+ type: 'VariableDeclarator',
163
+ id: { type: 'Identifier', name: 'OrgLayout' },
164
+ // @ts-expect-error
165
+ init: isDeclaration(child.declaration)
166
+ ? declarationToExpression(child.declaration)
167
+ : child.declaration
168
+ }
169
+ ]
170
+ })
171
+ }
172
+ // ```js
173
+ // export {a, b as c} from 'd'
174
+ // ```
175
+ else if (child.type === 'ExportNamedDeclaration' && child.source) {
176
+ const source = /** @type {SimpleLiteral} */ (child.source)
177
+
178
+ // Remove `default` or `as default`, but not `default as`, specifier.
179
+ child.specifiers = child.specifiers.filter((specifier) => {
180
+ // @ts-expect-error
181
+ if (specifier.exported.name === 'default') {
182
+ if (layout) {
183
+ file.fail(
184
+ 'Cannot specify multiple layouts (previous: ' +
185
+ stringifyPosition(positionFromEstree(layout)) +
186
+ ')',
187
+ positionFromEstree(child),
188
+ 'recma-document:duplicate-layout'
189
+ )
190
+ }
191
+
192
+ layout = specifier
193
+
194
+ // Make it just an import: `import OrgLayout from '…'`.
195
+ /** @type {Array<ImportDefaultSpecifier | ImportSpecifier>} */
196
+ const specifiers = []
197
+
198
+ // Default as default / something else as default.
199
+ // @ts-expect-error
200
+ if (specifier.local.name === 'default') {
201
+ specifiers.push({
202
+ type: 'ImportDefaultSpecifier',
203
+ local: { type: 'Identifier', name: 'OrgLayout' }
204
+ })
205
+ } else {
206
+ /** @type {ImportSpecifier} */
207
+ const importSpecifier = {
208
+ type: 'ImportSpecifier',
209
+ imported: specifier.local,
210
+ local: { type: 'Identifier', name: 'OrgLayout' }
211
+ }
212
+ create(specifier.local, importSpecifier)
213
+ specifiers.push(importSpecifier)
214
+ }
215
+
216
+ /** @type {Literal} */
217
+ const from = { type: 'Literal', value: source.value }
218
+ create(source, from)
219
+
220
+ /** @type {ImportDeclaration} */
221
+ const declaration = {
222
+ type: 'ImportDeclaration',
223
+ specifiers,
224
+ source: from
225
+ }
226
+ create(specifier, declaration)
227
+ handleEsm(declaration)
228
+
229
+ return false
230
+ }
231
+
232
+ return true
233
+ })
234
+
235
+ // If there are other things imported, keep it.
236
+ if (child.specifiers.length > 0) {
237
+ handleExport(child)
238
+ }
239
+ }
240
+ // ```js
241
+ // export {a, b as c}
242
+ // export * from 'a'
243
+ // ```
244
+ else if (
245
+ child.type === 'ExportNamedDeclaration' ||
246
+ child.type === 'ExportAllDeclaration'
247
+ ) {
248
+ handleExport(child)
249
+ } else if (child.type === 'ImportDeclaration') {
250
+ handleEsm(child)
251
+ } else if (
252
+ child.type === 'ExpressionStatement' &&
253
+ (child.expression.type === 'JSXFragment' ||
254
+ child.expression.type === 'JSXElement')
255
+ ) {
256
+ content = true
257
+ replacement.push(...createMdxContent(child.expression, Boolean(layout)))
258
+ // The following catch-all branch is because plugins might’ve added
259
+ // other things.
260
+ // Normally, we only have import/export/jsx, but just add whatever’s
261
+ // there.
262
+ /* c8 ignore next 3 */
263
+ } else {
264
+ replacement.push(child)
265
+ }
266
+ }
267
+
268
+ // If there was no JSX content at all, add an empty function.
269
+ if (!content) {
270
+ replacement.push(...createMdxContent(undefined, Boolean(layout)))
271
+ }
272
+
273
+ exportedIdentifiers.push(['OrgContent', 'default'])
274
+
275
+ if (outputFormat === 'function-body') {
276
+ replacement.push({
277
+ type: 'ReturnStatement',
278
+ argument: {
279
+ type: 'ObjectExpression',
280
+ properties: [
281
+ ...Array.from({ length: exportAllCount }).map(
282
+ /**
283
+ * @param {undefined} _
284
+ * @param {number} index
285
+ * @returns {SpreadElement}
286
+ */
287
+ (_, index) => ({
288
+ type: 'SpreadElement',
289
+ argument: {
290
+ type: 'Identifier',
291
+ name: `_exportAll${index + 1}`
292
+ }
293
+ })
294
+ ),
295
+ ...exportedIdentifiers.map((d) => {
296
+ /** @type {Property} */
297
+ const prop = {
298
+ type: 'Property',
299
+ kind: 'init',
300
+ method: false,
301
+ computed: false,
302
+ shorthand: typeof d === 'string',
303
+ key: {
304
+ type: 'Identifier',
305
+ name: typeof d === 'string' ? d : d[1]
306
+ },
307
+ value: {
308
+ type: 'Identifier',
309
+ name: typeof d === 'string' ? d : d[0]
310
+ }
311
+ }
312
+
313
+ return prop
314
+ })
315
+ ]
316
+ }
317
+ })
318
+ } else {
319
+ replacement.push({
320
+ type: 'ExportDefaultDeclaration',
321
+ declaration: { type: 'Identifier', name: 'OrgContent' }
322
+ })
323
+ }
324
+
325
+ tree.body = replacement
326
+
327
+ if (baseUrl) {
328
+ walk(tree, {
329
+ enter(node) {
330
+ if (
331
+ node.type === 'MemberExpression' &&
332
+ 'object' in node &&
333
+ node.object.type === 'MetaProperty' &&
334
+ node.property.type === 'Identifier' &&
335
+ node.object.meta.name === 'import' &&
336
+ node.object.property.name === 'meta' &&
337
+ node.property.name === 'url'
338
+ ) {
339
+ /** @type {SimpleLiteral} */
340
+ const replacement = { type: 'Literal', value: baseUrl }
341
+ this.replace(replacement)
342
+ }
343
+ }
344
+ })
345
+ }
346
+
347
+ /**
348
+ * @param {ExportAllDeclaration | ExportNamedDeclaration} node
349
+ * @returns {void}
350
+ */
351
+ function handleExport(node) {
352
+ if (node.type === 'ExportNamedDeclaration') {
353
+ // ```js
354
+ // export function a() {}
355
+ // export class A {}
356
+ // export var a = 1
357
+ // ```
358
+ if (node.declaration) {
359
+ exportedIdentifiers.push(
360
+ ...analyze(node.declaration).scope.declarations.keys()
361
+ )
362
+ }
363
+
364
+ // ```js
365
+ // export {a, b as c}
366
+ // export {a, b as c} from 'd'
367
+ // ```
368
+ for (child of node.specifiers) {
369
+ // @ts-expect-error
370
+ exportedIdentifiers.push(child.exported.name)
371
+ }
372
+ }
373
+
374
+ handleEsm(node)
375
+ }
376
+
377
+ /**
378
+ * @param {ExportAllDeclaration | ExportNamedDeclaration | ImportDeclaration} node
379
+ * @returns {void}
380
+ */
381
+ function handleEsm(node) {
382
+ // Rewrite the source of the `import` / `export … from`.
383
+ // See: <https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier>
384
+ if (baseUrl && node.source) {
385
+ let value = String(node.source.value)
386
+
387
+ try {
388
+ // A full valid URL.
389
+ value = String(new URL(value))
390
+ } catch {
391
+ // Relative: `/example.js`, `./example.js`, and `../example.js`.
392
+ if (/^\.{0,2}\//.test(value)) {
393
+ value = String(new URL(value, baseUrl))
394
+ }
395
+ // Otherwise, it’s a bare specifiers.
396
+ // For example `some-package`, `@some-package`, and
397
+ // `some-package/path`.
398
+ // These are supported in Node and browsers plan to support them
399
+ // with import maps (<https://github.com/WICG/import-maps>).
400
+ }
401
+
402
+ /** @type {Literal} */
403
+ const literal = { type: 'Literal', value }
404
+ create(node.source, literal)
405
+ node.source = literal
406
+ }
407
+
408
+ /** @type {ModuleDeclaration | Statement | undefined} */
409
+ let replace
410
+ /** @type {Expression} */
411
+ let init
412
+
413
+ if (outputFormat === 'function-body') {
414
+ if (
415
+ // Always have a source:
416
+ node.type === 'ImportDeclaration' ||
417
+ node.type === 'ExportAllDeclaration' ||
418
+ // Source optional:
419
+ (node.type === 'ExportNamedDeclaration' && node.source)
420
+ ) {
421
+ if (!useDynamicImport) {
422
+ file.fail(
423
+ 'Cannot use `import` or `export … from` in `evaluate` (outputting a function body) by default: please set `useDynamicImport: true` (and probably specify a `baseUrl`)',
424
+ positionFromEstree(node),
425
+ 'recma-document:invalid-esm-statement'
426
+ )
427
+ }
428
+
429
+ // Just for types.
430
+ /* c8 ignore next 3 */
431
+ if (!node.source) {
432
+ throw new Error('Expected `node.source` to be defined')
433
+ }
434
+
435
+ // ```
436
+ // import 'a'
437
+ // //=> await import('a')
438
+ // import a from 'b'
439
+ // //=> const {default: a} = await import('b')
440
+ // export {a, b as c} from 'd'
441
+ // //=> const {a, c: b} = await import('d')
442
+ // export * from 'a'
443
+ // //=> const _exportAll0 = await import('a')
444
+ // ```
445
+ /** @type {ImportExpression} */
446
+ const argument = { type: 'ImportExpression', source: node.source }
447
+ create(node, argument)
448
+ init = { type: 'AwaitExpression', argument }
449
+
450
+ if (
451
+ (node.type === 'ImportDeclaration' ||
452
+ node.type === 'ExportNamedDeclaration') &&
453
+ node.specifiers.length === 0
454
+ ) {
455
+ replace = { type: 'ExpressionStatement', expression: init }
456
+ } else {
457
+ replace = {
458
+ type: 'VariableDeclaration',
459
+ kind: 'const',
460
+ declarations:
461
+ node.type === 'ExportAllDeclaration'
462
+ ? [
463
+ {
464
+ type: 'VariableDeclarator',
465
+ id: {
466
+ type: 'Identifier',
467
+ name: `_exportAll${++exportAllCount}`
468
+ },
469
+ init
470
+ }
471
+ ]
472
+ : specifiersToDeclarations(node.specifiers, init)
473
+ }
474
+ }
475
+ } else if (node.declaration) {
476
+ replace = node.declaration
477
+ } else {
478
+ /** @type {Array<VariableDeclarator>} */
479
+ // @ts-expect-error
480
+ const declarators = node.specifiers
481
+ .filter(
482
+ // @ts-expect-error
483
+ (specifier) => specifier.local.name !== specifier.exported.name
484
+ )
485
+ .map((specifier) => ({
486
+ type: 'VariableDeclarator',
487
+ id: specifier.exported,
488
+ init: specifier.local
489
+ }))
490
+
491
+ if (declarators.length > 0) {
492
+ replace = {
493
+ type: 'VariableDeclaration',
494
+ kind: 'const',
495
+ declarations: declarators
496
+ }
497
+ }
498
+ }
499
+ } else {
500
+ replace = node
501
+ }
502
+
503
+ if (replace) {
504
+ replacement.push(replace)
505
+ }
506
+ }
507
+ }
508
+
509
+ /**
510
+ * @param {Expression | undefined} [content]
511
+ * @param {boolean | undefined} [hasInternalLayout]
512
+ * @returns {Array<FunctionDeclaration>}
513
+ */
514
+ function createMdxContent(content, hasInternalLayout) {
515
+ /** @type {JSXElement} */
516
+ const element = {
517
+ type: 'JSXElement',
518
+ openingElement: {
519
+ type: 'JSXOpeningElement',
520
+ name: { type: 'JSXIdentifier', name: 'OrgLayout' },
521
+ attributes: [
522
+ {
523
+ type: 'JSXSpreadAttribute',
524
+ argument: { type: 'Identifier', name: 'props' }
525
+ }
526
+ ],
527
+ selfClosing: false
528
+ },
529
+ closingElement: {
530
+ type: 'JSXClosingElement',
531
+ name: { type: 'JSXIdentifier', name: 'OrgLayout' }
532
+ },
533
+ children: [
534
+ {
535
+ type: 'JSXElement',
536
+ openingElement: {
537
+ type: 'JSXOpeningElement',
538
+ name: { type: 'JSXIdentifier', name: '_createOrgContent' },
539
+ attributes: [
540
+ {
541
+ type: 'JSXSpreadAttribute',
542
+ argument: { type: 'Identifier', name: 'props' }
543
+ }
544
+ ],
545
+ selfClosing: true
546
+ },
547
+ closingElement: null,
548
+ children: []
549
+ }
550
+ ]
551
+ }
552
+
553
+ let result = /** @type {Expression} */ (element)
554
+
555
+ if (!hasInternalLayout) {
556
+ result = {
557
+ type: 'ConditionalExpression',
558
+ test: { type: 'Identifier', name: 'OrgLayout' },
559
+ consequent: result,
560
+ alternate: {
561
+ type: 'CallExpression',
562
+ callee: { type: 'Identifier', name: '_createOrgContent' },
563
+ arguments: [{ type: 'Identifier', name: 'props' }],
564
+ optional: false
565
+ }
566
+ }
567
+ }
568
+
569
+ let argument = content || { type: 'Literal', value: null }
570
+
571
+ // Unwrap a fragment of a single element.
572
+ if (
573
+ argument &&
574
+ argument.type === 'JSXFragment' &&
575
+ argument.children.length === 1 &&
576
+ argument.children[0].type === 'JSXElement'
577
+ ) {
578
+ argument = argument.children[0]
579
+ }
580
+
581
+ return [
582
+ {
583
+ type: 'FunctionDeclaration',
584
+ id: { type: 'Identifier', name: '_createOrgContent' },
585
+ params: [{ type: 'Identifier', name: 'props' }],
586
+ body: {
587
+ type: 'BlockStatement',
588
+ body: [{ type: 'ReturnStatement', argument }]
589
+ }
590
+ },
591
+ {
592
+ type: 'FunctionDeclaration',
593
+ id: { type: 'Identifier', name: 'OrgContent' },
594
+ params: [
595
+ {
596
+ type: 'AssignmentPattern',
597
+ left: { type: 'Identifier', name: 'props' },
598
+ right: { type: 'ObjectExpression', properties: [] }
599
+ }
600
+ ],
601
+ body: {
602
+ type: 'BlockStatement',
603
+ body: [{ type: 'ReturnStatement', argument: result }]
604
+ }
605
+ }
606
+ ]
607
+ }
608
608
  }