@orgajs/orgx 1.0.7 → 2.0.0
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.
- package/LICENSE.org +22 -0
- package/dist/index.d.ts +11 -5
- package/dist/lib/compile.d.ts +45 -0
- package/dist/lib/condition.browser.d.ts +1 -0
- package/dist/lib/condition.d.ts +1 -0
- package/dist/lib/core.d.ts +57 -0
- package/dist/lib/evaluate.d.ts +27 -0
- package/dist/lib/plugin/recma-document.d.ts +63 -0
- package/dist/lib/plugin/recma-jsx-build.d.ts +14 -0
- package/dist/lib/plugin/recma-jsx-rewrite.d.ts +50 -0
- package/dist/lib/plugin/recma-stringify.d.ts +13 -0
- package/dist/lib/plugin/rehype-recma.d.ts +49 -0
- package/dist/lib/run.d.ts +26 -0
- package/dist/lib/util/estree-util-create.d.ts +13 -0
- package/dist/lib/util/estree-util-declaration-to-expression.d.ts +19 -0
- package/dist/lib/util/estree-util-is-declaration.d.ts +15 -0
- package/dist/lib/util/estree-util-specifiers-to-declarations.d.ts +14 -0
- package/dist/lib/util/estree-util-to-binary-addition.d.ts +8 -0
- package/dist/lib/util/estree-util-to-id-or-member-expression.d.ts +11 -0
- package/dist/lib/util/render-error.d.ts +2 -0
- package/dist/lib/util/resolve-evaluate-options.d.ts +66 -0
- package/dist/lib/util/resolve-file-and-options.d.ts +16 -0
- package/index.js +14 -0
- package/lib/compile.js +54 -0
- package/lib/condition.browser.js +1 -0
- package/lib/condition.js +3 -0
- package/lib/core.js +100 -0
- package/lib/evaluate.js +41 -0
- package/lib/plugin/recma-document.js +607 -0
- package/lib/plugin/recma-jsx-build.js +53 -0
- package/lib/plugin/recma-jsx-rewrite.js +616 -0
- package/lib/plugin/recma-stringify.js +42 -0
- package/lib/plugin/rehype-recma.js +218 -0
- package/lib/run.js +31 -0
- package/lib/types.d.ts +46 -0
- package/lib/util/estree-util-create.js +27 -0
- package/lib/util/estree-util-declaration-to-expression.js +32 -0
- package/lib/util/estree-util-is-declaration.js +20 -0
- package/lib/util/estree-util-specifiers-to-declarations.js +90 -0
- package/lib/util/estree-util-to-binary-addition.js +23 -0
- package/lib/util/estree-util-to-id-or-member-expression.js +108 -0
- package/lib/util/render-error.js +91 -0
- package/lib/util/resolve-evaluate-options.js +64 -0
- package/lib/util/resolve-file-and-options.js +40 -0
- package/package.json +36 -29
- package/CHANGELOG.md +0 -71
- package/dist/compile.d.ts +0 -6
- package/dist/compile.d.ts.map +0 -1
- package/dist/compile.js +0 -12
- package/dist/compile.js.map +0 -1
- package/dist/estree/create.d.ts +0 -2
- package/dist/estree/create.d.ts.map +0 -1
- package/dist/estree/create.js +0 -14
- package/dist/estree/create.js.map +0 -1
- package/dist/estree/declaration-to-expression.d.ts +0 -3
- package/dist/estree/declaration-to-expression.d.ts.map +0 -1
- package/dist/estree/declaration-to-expression.js +0 -12
- package/dist/estree/declaration-to-expression.js.map +0 -1
- package/dist/estree/error.d.ts +0 -61
- package/dist/estree/error.d.ts.map +0 -1
- package/dist/estree/error.js +0 -87
- package/dist/estree/error.js.map +0 -1
- package/dist/estree/is-declaration.d.ts +0 -3
- package/dist/estree/is-declaration.d.ts.map +0 -1
- package/dist/estree/is-declaration.js +0 -9
- package/dist/estree/is-declaration.js.map +0 -1
- package/dist/estree/position-from-estree.d.ts +0 -13
- package/dist/estree/position-from-estree.d.ts.map +0 -1
- package/dist/estree/position-from-estree.js +0 -34
- package/dist/estree/position-from-estree.js.map +0 -1
- package/dist/estree/specifiers-to-object-pattern.d.ts +0 -5
- package/dist/estree/specifiers-to-object-pattern.d.ts.map +0 -1
- package/dist/estree/specifiers-to-object-pattern.js +0 -33
- package/dist/estree/specifiers-to-object-pattern.js.map +0 -1
- package/dist/evaluate.d.ts +0 -22
- package/dist/evaluate.d.ts.map +0 -1
- package/dist/evaluate.js +0 -27
- package/dist/evaluate.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -11
- package/dist/index.js.map +0 -1
- package/dist/plugin/estree-jsx-build.d.ts +0 -6
- package/dist/plugin/estree-jsx-build.d.ts.map +0 -1
- package/dist/plugin/estree-jsx-build.js +0 -38
- package/dist/plugin/estree-jsx-build.js.map +0 -1
- package/dist/plugin/estree-jsx-rewrite.d.ts +0 -6
- package/dist/plugin/estree-jsx-rewrite.d.ts.map +0 -1
- package/dist/plugin/estree-jsx-rewrite.js +0 -214
- package/dist/plugin/estree-jsx-rewrite.js.map +0 -1
- package/dist/plugin/estree-stringify.d.ts +0 -2
- package/dist/plugin/estree-stringify.d.ts.map +0 -1
- package/dist/plugin/estree-stringify.js +0 -127
- package/dist/plugin/estree-stringify.js.map +0 -1
- package/dist/plugin/estree-wrap-in-content.d.ts +0 -18
- package/dist/plugin/estree-wrap-in-content.d.ts.map +0 -1
- package/dist/plugin/estree-wrap-in-content.js +0 -375
- package/dist/plugin/estree-wrap-in-content.js.map +0 -1
- package/dist/plugin/rehype-estree.d.ts +0 -12
- package/dist/plugin/rehype-estree.d.ts.map +0 -1
- package/dist/plugin/rehype-estree.js +0 -122
- package/dist/plugin/rehype-estree.js.map +0 -1
- package/dist/plugin/rehype-set-layout.d.ts +0 -6
- package/dist/plugin/rehype-set-layout.d.ts.map +0 -1
- package/dist/plugin/rehype-set-layout.js +0 -30
- package/dist/plugin/rehype-set-layout.js.map +0 -1
- package/dist/processor.d.ts +0 -14
- package/dist/processor.d.ts.map +0 -1
- package/dist/processor.js +0 -52
- package/dist/processor.js.map +0 -1
- package/dist/utils/remove-quotes.d.ts +0 -3
- package/dist/utils/remove-quotes.d.ts.map +0 -1
- package/dist/utils/remove-quotes.js +0 -6
- package/dist/utils/remove-quotes.js.map +0 -1
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('estree-jsx').Expression} Expression
|
|
3
|
+
* @typedef {import('estree-jsx').Function} EstreeFunction
|
|
4
|
+
* @typedef {import('estree-jsx').Identifier} Identifier
|
|
5
|
+
* @typedef {import('estree-jsx').ImportSpecifier} ImportSpecifier
|
|
6
|
+
* @typedef {import('estree-jsx').JSXElement} JSXElement
|
|
7
|
+
* @typedef {import('estree-jsx').ModuleDeclaration} ModuleDeclaration
|
|
8
|
+
* @typedef {import('estree-jsx').Node} Node
|
|
9
|
+
* @typedef {import('estree-jsx').ObjectPattern} ObjectPattern
|
|
10
|
+
* @typedef {import('estree-jsx').Program} Program
|
|
11
|
+
* @typedef {import('estree-jsx').Property} Property
|
|
12
|
+
* @typedef {import('estree-jsx').Statement} Statement
|
|
13
|
+
* @typedef {import('estree-jsx').VariableDeclarator} VariableDeclarator
|
|
14
|
+
*
|
|
15
|
+
* @typedef {import('periscopic').Scope & {node: Node}} Scope
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @typedef RecmaJsxRewriteOptions
|
|
20
|
+
* Configuration for internal plugin `recma-jsx-rewrite`.
|
|
21
|
+
* @property {'function-body' | 'program' | null | undefined} [outputFormat='program']
|
|
22
|
+
* Whether to use an import statement or `arguments[0]` to get the provider.
|
|
23
|
+
* @property {string | null | undefined} [providerImportSource]
|
|
24
|
+
* Place to import a provider from.
|
|
25
|
+
* @property {boolean | null | undefined} [development=false]
|
|
26
|
+
* Whether to add extra info to error messages in generated code.
|
|
27
|
+
*
|
|
28
|
+
* This also results in the development automatic JSX runtime
|
|
29
|
+
* (`/jsx-dev-runtime`, `jsxDEV`) being used, which passes positional info to
|
|
30
|
+
* nodes.
|
|
31
|
+
* The default can be set to `true` in Node.js through environment variables:
|
|
32
|
+
* set `NODE_ENV=development`.
|
|
33
|
+
*
|
|
34
|
+
* @typedef StackEntry
|
|
35
|
+
* @property {Array<string>} objects
|
|
36
|
+
* @property {Array<string>} components
|
|
37
|
+
* @property {Array<string>} tags
|
|
38
|
+
* @property {Record<string, {node: JSXElement, component: boolean}>} references
|
|
39
|
+
* @property {Map<string|number, string>} idToInvalidComponentName
|
|
40
|
+
* @property {EstreeFunction} node
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
import { stringifyPosition } from 'unist-util-stringify-position'
|
|
44
|
+
import { positionFromEstree } from 'unist-util-position-from-estree'
|
|
45
|
+
import { name as isIdentifierName } from 'estree-util-is-identifier-name'
|
|
46
|
+
import { walk } from 'estree-walker'
|
|
47
|
+
import { analyze } from 'periscopic'
|
|
48
|
+
import { specifiersToDeclarations } from '../util/estree-util-specifiers-to-declarations.js'
|
|
49
|
+
import {
|
|
50
|
+
toIdOrMemberExpression,
|
|
51
|
+
toJsxIdOrMemberExpression,
|
|
52
|
+
} from '../util/estree-util-to-id-or-member-expression.js'
|
|
53
|
+
import { toBinaryAddition } from '../util/estree-util-to-binary-addition.js'
|
|
54
|
+
|
|
55
|
+
const own = {}.hasOwnProperty
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* A plugin that rewrites JSX in functions to accept components as
|
|
59
|
+
* `props.components` (when the function is called `_createOrgContent`), or from
|
|
60
|
+
* a provider (if there is one).
|
|
61
|
+
* It also makes sure that any undefined components are defined: either from
|
|
62
|
+
* received components or as a function that throws an error.
|
|
63
|
+
*
|
|
64
|
+
* @type {import('unified').Plugin<[RecmaJsxRewriteOptions | null | undefined] | [], Program>}
|
|
65
|
+
*/
|
|
66
|
+
export function recmaJsxRewrite(options) {
|
|
67
|
+
// Always given inside `@mdx-js/mdx`
|
|
68
|
+
/* c8 ignore next */
|
|
69
|
+
const { development, providerImportSource, outputFormat } = options || {}
|
|
70
|
+
|
|
71
|
+
return (tree, file) => {
|
|
72
|
+
// Find everything that’s defined in the top-level scope.
|
|
73
|
+
const scopeInfo = analyze(tree)
|
|
74
|
+
/** @type {Array<StackEntry>} */
|
|
75
|
+
const fnStack = []
|
|
76
|
+
let importProvider = false
|
|
77
|
+
let createErrorHelper = false
|
|
78
|
+
/** @type {Scope | undefined} */
|
|
79
|
+
let currentScope
|
|
80
|
+
|
|
81
|
+
walk(tree, {
|
|
82
|
+
enter(node) {
|
|
83
|
+
const newScope = /** @type {Scope | undefined} */ (
|
|
84
|
+
scopeInfo.map.get(node)
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
node.type === 'FunctionDeclaration' ||
|
|
89
|
+
node.type === 'FunctionExpression' ||
|
|
90
|
+
node.type === 'ArrowFunctionExpression'
|
|
91
|
+
) {
|
|
92
|
+
fnStack.push({
|
|
93
|
+
objects: [],
|
|
94
|
+
components: [],
|
|
95
|
+
tags: [],
|
|
96
|
+
references: {},
|
|
97
|
+
idToInvalidComponentName: new Map(),
|
|
98
|
+
node,
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
// OrgContent only ever contains OrgLayout
|
|
102
|
+
if (
|
|
103
|
+
isNamedFunction(node, 'OrgContent') &&
|
|
104
|
+
newScope &&
|
|
105
|
+
!inScope(newScope, 'OrgLayout')
|
|
106
|
+
) {
|
|
107
|
+
fnStack[0].components.push('OrgLayout')
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const fnScope = fnStack[0]
|
|
112
|
+
if (
|
|
113
|
+
!fnScope ||
|
|
114
|
+
(!isNamedFunction(fnScope.node, '_createOrgContent') &&
|
|
115
|
+
!providerImportSource)
|
|
116
|
+
) {
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (newScope) {
|
|
121
|
+
newScope.node = node
|
|
122
|
+
currentScope = newScope
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (currentScope && node.type === 'JSXElement') {
|
|
126
|
+
let name = node.openingElement.name
|
|
127
|
+
|
|
128
|
+
// `<x.y>`, `<Foo.Bar>`, `<x.y.z>`.
|
|
129
|
+
if (name.type === 'JSXMemberExpression') {
|
|
130
|
+
/** @type {Array<string>} */
|
|
131
|
+
const ids = []
|
|
132
|
+
|
|
133
|
+
// Find the left-most identifier.
|
|
134
|
+
while (name.type === 'JSXMemberExpression') {
|
|
135
|
+
ids.unshift(name.property.name)
|
|
136
|
+
name = name.object
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
ids.unshift(name.name)
|
|
140
|
+
const fullId = ids.join('.')
|
|
141
|
+
const id = name.name
|
|
142
|
+
|
|
143
|
+
const isInScope = inScope(currentScope, id)
|
|
144
|
+
|
|
145
|
+
if (!own.call(fnScope.references, fullId)) {
|
|
146
|
+
const parentScope = /** @type {Scope | undefined} */ (
|
|
147
|
+
currentScope.parent
|
|
148
|
+
)
|
|
149
|
+
if (
|
|
150
|
+
!isInScope ||
|
|
151
|
+
// If the parent scope is `_createOrgContent`, then this
|
|
152
|
+
// references a component we can add a check statement for.
|
|
153
|
+
(parentScope &&
|
|
154
|
+
parentScope.node.type === 'FunctionDeclaration' &&
|
|
155
|
+
isNamedFunction(parentScope.node, '_createOrgContent'))
|
|
156
|
+
) {
|
|
157
|
+
fnScope.references[fullId] = { node, component: true }
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (!fnScope.objects.includes(id) && !isInScope) {
|
|
162
|
+
fnScope.objects.push(id)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// `<xml:thing>`.
|
|
166
|
+
else if (name.type === 'JSXNamespacedName') {
|
|
167
|
+
// Ignore namespaces.
|
|
168
|
+
}
|
|
169
|
+
// If the name is a valid ES identifier, and it doesn’t start with a
|
|
170
|
+
// lowercase letter, it’s a component.
|
|
171
|
+
// For example, `$foo`, `_bar`, `Baz` are all component names.
|
|
172
|
+
// But `foo` and `b-ar` are tag names.
|
|
173
|
+
else if (isIdentifierName(name.name) && !/^[a-z]/.test(name.name)) {
|
|
174
|
+
const id = name.name
|
|
175
|
+
|
|
176
|
+
if (!inScope(currentScope, id)) {
|
|
177
|
+
// No need to add an error for an undefined layout — we use an
|
|
178
|
+
// `if` later.
|
|
179
|
+
if (id !== 'OrgLayout' && !own.call(fnScope.references, id)) {
|
|
180
|
+
fnScope.references[id] = { node, component: true }
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (!fnScope.components.includes(id)) {
|
|
184
|
+
fnScope.components.push(id)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// @ts-expect-error Allow fields passed through from mdast through hast to
|
|
189
|
+
// esast.
|
|
190
|
+
else if (node.data && node.data._mdxExplicitJsx) {
|
|
191
|
+
// Do not turn explicit JSX into components from `_components`.
|
|
192
|
+
// As in, a given `h1` component is used for `# heading` (next case),
|
|
193
|
+
// but not for `<h1>heading</h1>`.
|
|
194
|
+
} else {
|
|
195
|
+
const id = name.name
|
|
196
|
+
|
|
197
|
+
if (!fnScope.tags.includes(id)) {
|
|
198
|
+
fnScope.tags.push(id)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** @type {Array<string | number>} */
|
|
202
|
+
let jsxIdExpression = ['_components', id]
|
|
203
|
+
if (isIdentifierName(id) === false) {
|
|
204
|
+
let invalidComponentName =
|
|
205
|
+
fnScope.idToInvalidComponentName.get(id)
|
|
206
|
+
if (invalidComponentName === undefined) {
|
|
207
|
+
invalidComponentName = `_component${fnScope.idToInvalidComponentName.size}`
|
|
208
|
+
fnScope.idToInvalidComponentName.set(id, invalidComponentName)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
jsxIdExpression = [invalidComponentName]
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
node.openingElement.name =
|
|
215
|
+
toJsxIdOrMemberExpression(jsxIdExpression)
|
|
216
|
+
|
|
217
|
+
if (node.closingElement) {
|
|
218
|
+
node.closingElement.name =
|
|
219
|
+
toJsxIdOrMemberExpression(jsxIdExpression)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
leave(node) {
|
|
225
|
+
/** @type {Array<Property>} */
|
|
226
|
+
const defaults = []
|
|
227
|
+
/** @type {Array<string>} */
|
|
228
|
+
const actual = []
|
|
229
|
+
/** @type {Array<Expression>} */
|
|
230
|
+
const parameters = []
|
|
231
|
+
/** @type {Array<VariableDeclarator>} */
|
|
232
|
+
const declarations = []
|
|
233
|
+
|
|
234
|
+
if (currentScope && currentScope.node === node) {
|
|
235
|
+
// @ts-expect-error: `node`s were patched when entering.
|
|
236
|
+
currentScope = currentScope.parent
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (
|
|
240
|
+
node.type === 'FunctionDeclaration' ||
|
|
241
|
+
node.type === 'FunctionExpression' ||
|
|
242
|
+
node.type === 'ArrowFunctionExpression'
|
|
243
|
+
) {
|
|
244
|
+
const fn = node
|
|
245
|
+
const scope = fnStack[fnStack.length - 1]
|
|
246
|
+
/** @type {string} */
|
|
247
|
+
let name
|
|
248
|
+
|
|
249
|
+
for (name of scope.tags) {
|
|
250
|
+
defaults.push({
|
|
251
|
+
type: 'Property',
|
|
252
|
+
kind: 'init',
|
|
253
|
+
key: isIdentifierName(name)
|
|
254
|
+
? { type: 'Identifier', name }
|
|
255
|
+
: { type: 'Literal', value: name },
|
|
256
|
+
value: { type: 'Literal', value: name },
|
|
257
|
+
method: false,
|
|
258
|
+
shorthand: false,
|
|
259
|
+
computed: false,
|
|
260
|
+
})
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
actual.push(...scope.components)
|
|
264
|
+
|
|
265
|
+
for (name of scope.objects) {
|
|
266
|
+
// In some cases, a component is used directly (`<X>`) but it’s also
|
|
267
|
+
// used as an object (`<X.Y>`).
|
|
268
|
+
if (!actual.includes(name)) {
|
|
269
|
+
actual.push(name)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** @type {Array<Statement>} */
|
|
274
|
+
const statements = []
|
|
275
|
+
|
|
276
|
+
if (
|
|
277
|
+
defaults.length > 0 ||
|
|
278
|
+
actual.length > 0 ||
|
|
279
|
+
scope.idToInvalidComponentName.size > 0
|
|
280
|
+
) {
|
|
281
|
+
if (providerImportSource) {
|
|
282
|
+
importProvider = true
|
|
283
|
+
parameters.push({
|
|
284
|
+
type: 'CallExpression',
|
|
285
|
+
callee: { type: 'Identifier', name: '_provideComponents' },
|
|
286
|
+
arguments: [],
|
|
287
|
+
optional: false,
|
|
288
|
+
})
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Accept `components` as a prop if this is the `OrgContent` or
|
|
292
|
+
// `_createOrgContent` function.
|
|
293
|
+
if (
|
|
294
|
+
isNamedFunction(scope.node, 'OrgContent') ||
|
|
295
|
+
isNamedFunction(scope.node, '_createOrgContent')
|
|
296
|
+
) {
|
|
297
|
+
parameters.push(toIdOrMemberExpression(['props', 'components']))
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (defaults.length > 0 || parameters.length > 1) {
|
|
301
|
+
parameters.unshift({
|
|
302
|
+
type: 'ObjectExpression',
|
|
303
|
+
properties: defaults,
|
|
304
|
+
})
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// If we’re getting components from several sources, merge them.
|
|
308
|
+
/** @type {Expression} */
|
|
309
|
+
let componentsInit =
|
|
310
|
+
parameters.length > 1
|
|
311
|
+
? {
|
|
312
|
+
type: 'CallExpression',
|
|
313
|
+
callee: toIdOrMemberExpression(['Object', 'assign']),
|
|
314
|
+
arguments: parameters,
|
|
315
|
+
optional: false,
|
|
316
|
+
}
|
|
317
|
+
: parameters[0].type === 'MemberExpression'
|
|
318
|
+
? // If we’re only getting components from `props.components`,
|
|
319
|
+
// make sure it’s defined.
|
|
320
|
+
{
|
|
321
|
+
type: 'LogicalExpression',
|
|
322
|
+
operator: '||',
|
|
323
|
+
left: parameters[0],
|
|
324
|
+
right: { type: 'ObjectExpression', properties: [] },
|
|
325
|
+
}
|
|
326
|
+
: parameters[0]
|
|
327
|
+
|
|
328
|
+
/** @type {ObjectPattern | undefined} */
|
|
329
|
+
let componentsPattern
|
|
330
|
+
|
|
331
|
+
// Add components to scope.
|
|
332
|
+
// For `['MyComponent', 'OrgLayout']` this generates:
|
|
333
|
+
// ```js
|
|
334
|
+
// const {MyComponent, wrapper: OrgLayout} = _components
|
|
335
|
+
// ```
|
|
336
|
+
// Note that OrgLayout is special as it’s taken from
|
|
337
|
+
// `_components.wrapper`.
|
|
338
|
+
if (actual.length > 0) {
|
|
339
|
+
componentsPattern = {
|
|
340
|
+
type: 'ObjectPattern',
|
|
341
|
+
properties: actual.map((name) => ({
|
|
342
|
+
type: 'Property',
|
|
343
|
+
kind: 'init',
|
|
344
|
+
key: {
|
|
345
|
+
type: 'Identifier',
|
|
346
|
+
name: name === 'OrgLayout' ? 'wrapper' : name,
|
|
347
|
+
},
|
|
348
|
+
value: { type: 'Identifier', name },
|
|
349
|
+
method: false,
|
|
350
|
+
shorthand: name !== 'OrgLayout',
|
|
351
|
+
computed: false,
|
|
352
|
+
})),
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (scope.tags.length > 0) {
|
|
357
|
+
declarations.push({
|
|
358
|
+
type: 'VariableDeclarator',
|
|
359
|
+
id: { type: 'Identifier', name: '_components' },
|
|
360
|
+
init: componentsInit,
|
|
361
|
+
})
|
|
362
|
+
componentsInit = { type: 'Identifier', name: '_components' }
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (isNamedFunction(scope.node, '_createOrgContent')) {
|
|
366
|
+
for (const [
|
|
367
|
+
id,
|
|
368
|
+
componentName,
|
|
369
|
+
] of scope.idToInvalidComponentName) {
|
|
370
|
+
// For JSX IDs that can’t be represented as JavaScript IDs (as in,
|
|
371
|
+
// those with dashes, such as `custom-element`), generate a
|
|
372
|
+
// separate variable that is a valid JS ID (such as `_component0`),
|
|
373
|
+
// and takes it from components:
|
|
374
|
+
// `const _component0 = _components['custom-element']`
|
|
375
|
+
declarations.push({
|
|
376
|
+
type: 'VariableDeclarator',
|
|
377
|
+
id: { type: 'Identifier', name: componentName },
|
|
378
|
+
init: {
|
|
379
|
+
type: 'MemberExpression',
|
|
380
|
+
object: { type: 'Identifier', name: '_components' },
|
|
381
|
+
property: { type: 'Literal', value: id },
|
|
382
|
+
computed: true,
|
|
383
|
+
optional: false,
|
|
384
|
+
},
|
|
385
|
+
})
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (componentsPattern) {
|
|
390
|
+
declarations.push({
|
|
391
|
+
type: 'VariableDeclarator',
|
|
392
|
+
id: componentsPattern,
|
|
393
|
+
init: componentsInit,
|
|
394
|
+
})
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (declarations.length > 0) {
|
|
398
|
+
statements.push({
|
|
399
|
+
type: 'VariableDeclaration',
|
|
400
|
+
kind: 'const',
|
|
401
|
+
declarations,
|
|
402
|
+
})
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/** @type {string} */
|
|
407
|
+
let key
|
|
408
|
+
|
|
409
|
+
// Add partials (so for `x.y.z` it’d generate `x` and `x.y` too).
|
|
410
|
+
for (key in scope.references) {
|
|
411
|
+
if (own.call(scope.references, key)) {
|
|
412
|
+
const parts = key.split('.')
|
|
413
|
+
let index = 0
|
|
414
|
+
while (++index < parts.length) {
|
|
415
|
+
const partial = parts.slice(0, index).join('.')
|
|
416
|
+
if (!own.call(scope.references, partial)) {
|
|
417
|
+
scope.references[partial] = {
|
|
418
|
+
node: scope.references[key].node,
|
|
419
|
+
component: false,
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const references = Object.keys(scope.references).sort()
|
|
427
|
+
let index = -1
|
|
428
|
+
while (++index < references.length) {
|
|
429
|
+
const id = references[index]
|
|
430
|
+
const info = scope.references[id]
|
|
431
|
+
const place = stringifyPosition(positionFromEstree(info.node))
|
|
432
|
+
/** @type {Array<Expression>} */
|
|
433
|
+
const parameters = [
|
|
434
|
+
{ type: 'Literal', value: id },
|
|
435
|
+
{ type: 'Literal', value: info.component },
|
|
436
|
+
]
|
|
437
|
+
|
|
438
|
+
createErrorHelper = true
|
|
439
|
+
|
|
440
|
+
if (development && place !== '1:1-1:1') {
|
|
441
|
+
parameters.push({ type: 'Literal', value: place })
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
statements.push({
|
|
445
|
+
type: 'IfStatement',
|
|
446
|
+
test: {
|
|
447
|
+
type: 'UnaryExpression',
|
|
448
|
+
operator: '!',
|
|
449
|
+
prefix: true,
|
|
450
|
+
argument: toIdOrMemberExpression(id.split('.')),
|
|
451
|
+
},
|
|
452
|
+
consequent: {
|
|
453
|
+
type: 'ExpressionStatement',
|
|
454
|
+
expression: {
|
|
455
|
+
type: 'CallExpression',
|
|
456
|
+
callee: { type: 'Identifier', name: '_missingMdxReference' },
|
|
457
|
+
arguments: parameters,
|
|
458
|
+
optional: false,
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
alternate: null,
|
|
462
|
+
})
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (statements.length > 0) {
|
|
466
|
+
// Arrow functions with an implied return:
|
|
467
|
+
if (fn.body.type !== 'BlockStatement') {
|
|
468
|
+
fn.body = {
|
|
469
|
+
type: 'BlockStatement',
|
|
470
|
+
body: [{ type: 'ReturnStatement', argument: fn.body }],
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
fn.body.body.unshift(...statements)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
fnStack.pop()
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
// If a provider is used (and can be used), import it.
|
|
483
|
+
if (importProvider && providerImportSource) {
|
|
484
|
+
tree.body.unshift(
|
|
485
|
+
createImportProvider(providerImportSource, outputFormat)
|
|
486
|
+
)
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// If potentially missing components are used.
|
|
490
|
+
if (createErrorHelper) {
|
|
491
|
+
/** @type {Array<Expression>} */
|
|
492
|
+
const message = [
|
|
493
|
+
{ type: 'Literal', value: 'Expected ' },
|
|
494
|
+
{
|
|
495
|
+
type: 'ConditionalExpression',
|
|
496
|
+
test: { type: 'Identifier', name: 'component' },
|
|
497
|
+
consequent: { type: 'Literal', value: 'component' },
|
|
498
|
+
alternate: { type: 'Literal', value: 'object' },
|
|
499
|
+
},
|
|
500
|
+
{ type: 'Literal', value: ' `' },
|
|
501
|
+
{ type: 'Identifier', name: 'id' },
|
|
502
|
+
{
|
|
503
|
+
type: 'Literal',
|
|
504
|
+
value:
|
|
505
|
+
'` to be defined: you likely forgot to import, pass, or provide it.',
|
|
506
|
+
},
|
|
507
|
+
]
|
|
508
|
+
|
|
509
|
+
/** @type {Array<Identifier>} */
|
|
510
|
+
const parameters = [
|
|
511
|
+
{ type: 'Identifier', name: 'id' },
|
|
512
|
+
{ type: 'Identifier', name: 'component' },
|
|
513
|
+
]
|
|
514
|
+
|
|
515
|
+
if (development) {
|
|
516
|
+
message.push({
|
|
517
|
+
type: 'ConditionalExpression',
|
|
518
|
+
test: { type: 'Identifier', name: 'place' },
|
|
519
|
+
consequent: toBinaryAddition([
|
|
520
|
+
{ type: 'Literal', value: '\nIt’s referenced in your code at `' },
|
|
521
|
+
{ type: 'Identifier', name: 'place' },
|
|
522
|
+
{
|
|
523
|
+
type: 'Literal',
|
|
524
|
+
value: (file.path ? '` in `' + file.path : '') + '`',
|
|
525
|
+
},
|
|
526
|
+
]),
|
|
527
|
+
alternate: { type: 'Literal', value: '' },
|
|
528
|
+
})
|
|
529
|
+
|
|
530
|
+
parameters.push({ type: 'Identifier', name: 'place' })
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
tree.body.push({
|
|
534
|
+
type: 'FunctionDeclaration',
|
|
535
|
+
id: { type: 'Identifier', name: '_missingMdxReference' },
|
|
536
|
+
generator: false,
|
|
537
|
+
async: false,
|
|
538
|
+
params: parameters,
|
|
539
|
+
body: {
|
|
540
|
+
type: 'BlockStatement',
|
|
541
|
+
body: [
|
|
542
|
+
{
|
|
543
|
+
type: 'ThrowStatement',
|
|
544
|
+
argument: {
|
|
545
|
+
type: 'NewExpression',
|
|
546
|
+
callee: { type: 'Identifier', name: 'Error' },
|
|
547
|
+
arguments: [toBinaryAddition(message)],
|
|
548
|
+
},
|
|
549
|
+
},
|
|
550
|
+
],
|
|
551
|
+
},
|
|
552
|
+
})
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* @param {string} providerImportSource
|
|
559
|
+
* @param {RecmaJsxRewriteOptions['outputFormat']} outputFormat
|
|
560
|
+
* @returns {Statement | ModuleDeclaration}
|
|
561
|
+
*/
|
|
562
|
+
function createImportProvider(providerImportSource, outputFormat) {
|
|
563
|
+
/** @type {Array<ImportSpecifier>} */
|
|
564
|
+
const specifiers = [
|
|
565
|
+
{
|
|
566
|
+
type: 'ImportSpecifier',
|
|
567
|
+
imported: { type: 'Identifier', name: 'useMDXComponents' },
|
|
568
|
+
local: { type: 'Identifier', name: '_provideComponents' },
|
|
569
|
+
},
|
|
570
|
+
]
|
|
571
|
+
|
|
572
|
+
return outputFormat === 'function-body'
|
|
573
|
+
? {
|
|
574
|
+
type: 'VariableDeclaration',
|
|
575
|
+
kind: 'const',
|
|
576
|
+
declarations: specifiersToDeclarations(
|
|
577
|
+
specifiers,
|
|
578
|
+
toIdOrMemberExpression(['arguments', 0])
|
|
579
|
+
),
|
|
580
|
+
}
|
|
581
|
+
: {
|
|
582
|
+
type: 'ImportDeclaration',
|
|
583
|
+
specifiers,
|
|
584
|
+
source: { type: 'Literal', value: providerImportSource },
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* @param {EstreeFunction} node
|
|
590
|
+
* @param {string} name
|
|
591
|
+
* @returns {boolean}
|
|
592
|
+
*/
|
|
593
|
+
function isNamedFunction(node, name) {
|
|
594
|
+
return Boolean(node && 'id' in node && node.id && node.id.name === name)
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* @param {Scope} scope
|
|
599
|
+
* @param {string} id
|
|
600
|
+
* @returns {boolean}
|
|
601
|
+
*/
|
|
602
|
+
function inScope(scope, id) {
|
|
603
|
+
/** @type {Scope | undefined} */
|
|
604
|
+
let currentScope = scope
|
|
605
|
+
|
|
606
|
+
while (currentScope) {
|
|
607
|
+
if (currentScope.declarations.has(id)) {
|
|
608
|
+
return true
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// @ts-expect-error: `node`s have been added when entering.
|
|
612
|
+
currentScope = currentScope.parent
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
return false
|
|
616
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('estree-jsx').Program} Program
|
|
3
|
+
* @typedef {typeof import('source-map').SourceMapGenerator} SourceMapGenerator
|
|
4
|
+
*
|
|
5
|
+
* @typedef RecmaStringifyOptions
|
|
6
|
+
* Configuration for internal plugin `recma-stringify`.
|
|
7
|
+
* @property {SourceMapGenerator | null | undefined} [SourceMapGenerator]
|
|
8
|
+
* Generate a source map by passing a `SourceMapGenerator` from `source-map`
|
|
9
|
+
* in.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { toJs, jsx } from 'estree-util-to-js'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A plugin that adds an esast compiler: a small wrapper around `astring` to add
|
|
16
|
+
* support for serializing JSX.
|
|
17
|
+
*
|
|
18
|
+
* @this {import('unified').Processor}
|
|
19
|
+
* @type {import('unified').Plugin<[RecmaStringifyOptions | null | undefined] | [], Program, string>}
|
|
20
|
+
*/
|
|
21
|
+
export function recmaStringify(options) {
|
|
22
|
+
// Always given inside `@mdx-js/mdx`
|
|
23
|
+
/* c8 ignore next */
|
|
24
|
+
const { SourceMapGenerator } = options || {}
|
|
25
|
+
|
|
26
|
+
Object.assign(this, { Compiler: compiler })
|
|
27
|
+
|
|
28
|
+
/** @type {import('unified').CompilerFunction<Program, string>} */
|
|
29
|
+
function compiler(tree, file) {
|
|
30
|
+
const result = SourceMapGenerator
|
|
31
|
+
? toJs(tree, {
|
|
32
|
+
filePath: file.path || 'unknown.mdx',
|
|
33
|
+
SourceMapGenerator,
|
|
34
|
+
handlers: jsx,
|
|
35
|
+
})
|
|
36
|
+
: toJs(tree, { handlers: jsx })
|
|
37
|
+
|
|
38
|
+
file.map = result.map
|
|
39
|
+
|
|
40
|
+
return result.value
|
|
41
|
+
}
|
|
42
|
+
}
|