@mintlify/common 1.0.1227 → 1.0.1229
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/dist/mdx/plugins/remark/index.d.ts +1 -0
- package/dist/mdx/plugins/remark/index.js +1 -0
- package/dist/mdx/plugins/remark/pureTemplateComponents.d.ts +7 -0
- package/dist/mdx/plugins/remark/pureTemplateComponents.js +406 -0
- package/dist/mdx/plugins/remark/remarkMdxRemoveJs.js +34 -28
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Program } from 'estree-jsx';
|
|
2
|
+
import type { Root } from 'mdast';
|
|
3
|
+
export declare const TEMPLATE_BUILT_IN_COMPONENTS: ReadonlySet<string>;
|
|
4
|
+
type Statement = Program['body'][number];
|
|
5
|
+
export declare function getKeptEsmStatements(tree: Root): Set<Statement>;
|
|
6
|
+
export declare function extractIdentifierRef(estree: Program | undefined): string | null;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { visit } from 'unist-util-visit';
|
|
2
|
+
import { isMdxJsEsm } from '../../utils.js';
|
|
3
|
+
export const TEMPLATE_BUILT_IN_COMPONENTS = new Set([
|
|
4
|
+
'Accordion',
|
|
5
|
+
'AccordionGroup',
|
|
6
|
+
'Badge',
|
|
7
|
+
'Callout',
|
|
8
|
+
'Card',
|
|
9
|
+
'CardGroup',
|
|
10
|
+
'Check',
|
|
11
|
+
'CodeBlock',
|
|
12
|
+
'CodeGroup',
|
|
13
|
+
'Color',
|
|
14
|
+
'Column',
|
|
15
|
+
'Columns',
|
|
16
|
+
'Danger',
|
|
17
|
+
'Expandable',
|
|
18
|
+
'FileTree',
|
|
19
|
+
'Frame',
|
|
20
|
+
'GitHub',
|
|
21
|
+
'Github',
|
|
22
|
+
'Heading',
|
|
23
|
+
'Icon',
|
|
24
|
+
'Info',
|
|
25
|
+
'Latex',
|
|
26
|
+
'Link',
|
|
27
|
+
'MDX',
|
|
28
|
+
'Mermaid',
|
|
29
|
+
'Note',
|
|
30
|
+
'OptimizedVideo',
|
|
31
|
+
'Panel',
|
|
32
|
+
'ParamField',
|
|
33
|
+
'Prompt',
|
|
34
|
+
'RequestExample',
|
|
35
|
+
'ResponseExample',
|
|
36
|
+
'ResponseField',
|
|
37
|
+
'SnippetGroup',
|
|
38
|
+
'Step',
|
|
39
|
+
'Steps',
|
|
40
|
+
'Tab',
|
|
41
|
+
'Tabs',
|
|
42
|
+
'Tile',
|
|
43
|
+
'Tip',
|
|
44
|
+
'Tooltip',
|
|
45
|
+
'Tree',
|
|
46
|
+
'Update',
|
|
47
|
+
'Variation',
|
|
48
|
+
'View',
|
|
49
|
+
'Visibility',
|
|
50
|
+
'Warning',
|
|
51
|
+
'ZoomImage',
|
|
52
|
+
]);
|
|
53
|
+
const UNSAFE_TAGS = new Set([
|
|
54
|
+
'base',
|
|
55
|
+
'embed',
|
|
56
|
+
'form',
|
|
57
|
+
'frame',
|
|
58
|
+
'frameset',
|
|
59
|
+
'iframe',
|
|
60
|
+
'link',
|
|
61
|
+
'math',
|
|
62
|
+
'meta',
|
|
63
|
+
'noscript',
|
|
64
|
+
'object',
|
|
65
|
+
'portal',
|
|
66
|
+
'script',
|
|
67
|
+
'style',
|
|
68
|
+
'svg',
|
|
69
|
+
'template',
|
|
70
|
+
]);
|
|
71
|
+
const UNSAFE_ATTRIBUTES = new Set([
|
|
72
|
+
'action',
|
|
73
|
+
'dangerouslysetinnerhtml',
|
|
74
|
+
'formaction',
|
|
75
|
+
'ref',
|
|
76
|
+
'srcdoc',
|
|
77
|
+
'style',
|
|
78
|
+
]);
|
|
79
|
+
const MDX_CONTENT_LOCALS = new Set(['props']);
|
|
80
|
+
const VALUE_NAME = /^[a-z][\w$]*$/;
|
|
81
|
+
const COMPONENT_NAME = /^[A-Z]\w*$/;
|
|
82
|
+
const TAG_NAME = /^[a-z][a-z0-9]*$/;
|
|
83
|
+
const ATTRIBUTE_NAME = /^[a-zA-Z][a-zA-Z0-9-]*$/;
|
|
84
|
+
export function getKeptEsmStatements(tree) {
|
|
85
|
+
const components = new Map();
|
|
86
|
+
const kept = new Set();
|
|
87
|
+
const constantNames = new Set();
|
|
88
|
+
const esmBindings = new Set();
|
|
89
|
+
visit(tree, (node) => {
|
|
90
|
+
var _a;
|
|
91
|
+
if (!isMdxJsEsm(node) || !((_a = node.data) === null || _a === void 0 ? void 0 : _a.estree))
|
|
92
|
+
return;
|
|
93
|
+
const program = node.data.estree;
|
|
94
|
+
collectTopLevelBindings(program, esmBindings);
|
|
95
|
+
for (const statement of program.body) {
|
|
96
|
+
const constantName = getLiteralConstantName(statement);
|
|
97
|
+
if (constantName) {
|
|
98
|
+
kept.add(statement);
|
|
99
|
+
constantNames.add(constantName);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const componentName = getPureTemplateComponentName(statement);
|
|
103
|
+
if (componentName)
|
|
104
|
+
components.set(statement, componentName);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
if (components.size === 0)
|
|
108
|
+
return kept;
|
|
109
|
+
const { rejected, attributeStubNames } = scanContent(tree, new Set(components.values()), constantNames);
|
|
110
|
+
const shadowing = new Set([...esmBindings, ...attributeStubNames]);
|
|
111
|
+
for (const [statement, name] of components) {
|
|
112
|
+
if (rejected.has(name) || !usesOnlyUnshadowedBuiltIns(statement, shadowing))
|
|
113
|
+
continue;
|
|
114
|
+
kept.add(statement);
|
|
115
|
+
}
|
|
116
|
+
return kept;
|
|
117
|
+
}
|
|
118
|
+
function getLiteralConstantName(statement) {
|
|
119
|
+
var _a;
|
|
120
|
+
if (statement.type !== 'ExportNamedDeclaration')
|
|
121
|
+
return null;
|
|
122
|
+
const declaration = statement.declaration;
|
|
123
|
+
if ((declaration === null || declaration === void 0 ? void 0 : declaration.type) !== 'VariableDeclaration' || declaration.kind !== 'const')
|
|
124
|
+
return null;
|
|
125
|
+
const declarator = declaration.declarations[0];
|
|
126
|
+
if (declaration.declarations.length !== 1 || (declarator === null || declarator === void 0 ? void 0 : declarator.id.type) !== 'Identifier')
|
|
127
|
+
return null;
|
|
128
|
+
const name = declarator.id.name;
|
|
129
|
+
if (!VALUE_NAME.test(name) || MDX_CONTENT_LOCALS.has(name))
|
|
130
|
+
return null;
|
|
131
|
+
if (((_a = declarator.init) === null || _a === void 0 ? void 0 : _a.type) !== 'Literal')
|
|
132
|
+
return null;
|
|
133
|
+
const value = declarator.init.value;
|
|
134
|
+
const isPrimitive = typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
|
|
135
|
+
return isPrimitive ? name : null;
|
|
136
|
+
}
|
|
137
|
+
function getPureTemplateComponentName(statement) {
|
|
138
|
+
var _a, _b;
|
|
139
|
+
if (statement.type !== 'ExportNamedDeclaration' || !statement.declaration)
|
|
140
|
+
return null;
|
|
141
|
+
const declaration = statement.declaration;
|
|
142
|
+
let name;
|
|
143
|
+
let fn;
|
|
144
|
+
if (declaration.type === 'FunctionDeclaration') {
|
|
145
|
+
name = (_a = declaration.id) === null || _a === void 0 ? void 0 : _a.name;
|
|
146
|
+
fn = declaration;
|
|
147
|
+
}
|
|
148
|
+
else if (declaration.type === 'VariableDeclaration' &&
|
|
149
|
+
declaration.kind === 'const' &&
|
|
150
|
+
declaration.declarations.length === 1) {
|
|
151
|
+
const declarator = declaration.declarations[0];
|
|
152
|
+
if ((declarator === null || declarator === void 0 ? void 0 : declarator.id.type) !== 'Identifier')
|
|
153
|
+
return null;
|
|
154
|
+
if (((_b = declarator.init) === null || _b === void 0 ? void 0 : _b.type) !== 'ArrowFunctionExpression')
|
|
155
|
+
return null;
|
|
156
|
+
name = declarator.id.name;
|
|
157
|
+
fn = declarator.init;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
if (!name || !COMPONENT_NAME.test(name) || TEMPLATE_BUILT_IN_COMPONENTS.has(name))
|
|
163
|
+
return null;
|
|
164
|
+
if (fn.async || fn.generator)
|
|
165
|
+
return null;
|
|
166
|
+
const params = getParamNames(fn.params);
|
|
167
|
+
if (!params)
|
|
168
|
+
return null;
|
|
169
|
+
const root = getReturnedExpression(fn);
|
|
170
|
+
if ((root === null || root === void 0 ? void 0 : root.type) !== 'JSXElement' && (root === null || root === void 0 ? void 0 : root.type) !== 'JSXFragment')
|
|
171
|
+
return null;
|
|
172
|
+
return isPureElement(root, params) ? name : null;
|
|
173
|
+
}
|
|
174
|
+
function getParamNames(params) {
|
|
175
|
+
const names = new Set();
|
|
176
|
+
if (params.length === 0)
|
|
177
|
+
return names;
|
|
178
|
+
const param = params[0];
|
|
179
|
+
if (params.length > 1 || (param === null || param === void 0 ? void 0 : param.type) !== 'ObjectPattern')
|
|
180
|
+
return null;
|
|
181
|
+
for (const property of param.properties) {
|
|
182
|
+
if (property.type !== 'Property' || property.computed || !property.shorthand)
|
|
183
|
+
return null;
|
|
184
|
+
if (property.key.type !== 'Identifier' || property.value.type !== 'Identifier')
|
|
185
|
+
return null;
|
|
186
|
+
const name = property.key.name;
|
|
187
|
+
if (property.value.name !== name || !VALUE_NAME.test(name) || name in Object.prototype) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
names.add(name);
|
|
191
|
+
}
|
|
192
|
+
return names;
|
|
193
|
+
}
|
|
194
|
+
function getReturnedExpression(fn) {
|
|
195
|
+
var _a;
|
|
196
|
+
if (fn.body.type !== 'BlockStatement')
|
|
197
|
+
return fn.body;
|
|
198
|
+
const statement = fn.body.body[0];
|
|
199
|
+
if (fn.body.body.length !== 1 || (statement === null || statement === void 0 ? void 0 : statement.type) !== 'ReturnStatement')
|
|
200
|
+
return null;
|
|
201
|
+
return (_a = statement.argument) !== null && _a !== void 0 ? _a : null;
|
|
202
|
+
}
|
|
203
|
+
function isPureElement(node, params) {
|
|
204
|
+
if (node.type === 'JSXElement') {
|
|
205
|
+
const { name, attributes } = node.openingElement;
|
|
206
|
+
if (name.type !== 'JSXIdentifier' || !isSafeElementName(name.name))
|
|
207
|
+
return false;
|
|
208
|
+
if (!attributes.every((attribute) => isPureAttribute(attribute, params)))
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
return node.children.every((child) => isPureChild(child, params));
|
|
212
|
+
}
|
|
213
|
+
function isSafeElementName(name) {
|
|
214
|
+
if (TEMPLATE_BUILT_IN_COMPONENTS.has(name))
|
|
215
|
+
return true;
|
|
216
|
+
return TAG_NAME.test(name) && !UNSAFE_TAGS.has(name);
|
|
217
|
+
}
|
|
218
|
+
function isPureAttribute(attribute, params) {
|
|
219
|
+
if (attribute.type !== 'JSXAttribute' || attribute.name.type !== 'JSXIdentifier')
|
|
220
|
+
return false;
|
|
221
|
+
const name = attribute.name.name;
|
|
222
|
+
if (!ATTRIBUTE_NAME.test(name) ||
|
|
223
|
+
/^on/i.test(name) ||
|
|
224
|
+
UNSAFE_ATTRIBUTES.has(name.toLowerCase())) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
const value = attribute.value;
|
|
228
|
+
if (value === null)
|
|
229
|
+
return true;
|
|
230
|
+
if (value.type === 'Literal')
|
|
231
|
+
return typeof value.value === 'string';
|
|
232
|
+
if (value.type !== 'JSXExpressionContainer')
|
|
233
|
+
return false;
|
|
234
|
+
if (value.expression.type === 'JSXEmptyExpression')
|
|
235
|
+
return false;
|
|
236
|
+
return isPureValue(value.expression, params);
|
|
237
|
+
}
|
|
238
|
+
function isPureChild(child, params) {
|
|
239
|
+
switch (child.type) {
|
|
240
|
+
case 'JSXText':
|
|
241
|
+
return true;
|
|
242
|
+
case 'JSXElement':
|
|
243
|
+
case 'JSXFragment':
|
|
244
|
+
return isPureElement(child, params);
|
|
245
|
+
case 'JSXExpressionContainer':
|
|
246
|
+
return (child.expression.type === 'JSXEmptyExpression' || isPureValue(child.expression, params));
|
|
247
|
+
default:
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function isPureValue(node, params) {
|
|
252
|
+
switch (node.type) {
|
|
253
|
+
case 'Literal':
|
|
254
|
+
return typeof node.value === 'string' || typeof node.value === 'number';
|
|
255
|
+
case 'Identifier':
|
|
256
|
+
return params.has(node.name);
|
|
257
|
+
case 'TemplateLiteral':
|
|
258
|
+
return node.expressions.every((expression) => expression.type === 'Identifier' && params.has(expression.name));
|
|
259
|
+
default:
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function scanContent(tree, candidates, constantNames) {
|
|
264
|
+
const rejected = new Set();
|
|
265
|
+
const attributeStubNames = new Set();
|
|
266
|
+
visit(tree, (node) => {
|
|
267
|
+
var _a, _b, _c;
|
|
268
|
+
if (isMdxJsEsm(node))
|
|
269
|
+
return;
|
|
270
|
+
if ((node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') &&
|
|
271
|
+
'name' in node &&
|
|
272
|
+
typeof node.name === 'string') {
|
|
273
|
+
const memberRoot = node.name.split('.')[0];
|
|
274
|
+
if (memberRoot && memberRoot !== node.name && candidates.has(memberRoot)) {
|
|
275
|
+
rejected.add(memberRoot);
|
|
276
|
+
}
|
|
277
|
+
if (candidates.has(node.name) && 'attributes' in node) {
|
|
278
|
+
const hasOnlyLiteralAttributes = node.attributes.every((attribute) => {
|
|
279
|
+
var _a;
|
|
280
|
+
return attribute.type === 'mdxJsxAttribute' &&
|
|
281
|
+
(attribute.value == null ||
|
|
282
|
+
typeof attribute.value === 'string' ||
|
|
283
|
+
isConstantReference((_a = attribute.value.data) === null || _a === void 0 ? void 0 : _a.estree, constantNames));
|
|
284
|
+
});
|
|
285
|
+
if (!hasOnlyLiteralAttributes)
|
|
286
|
+
rejected.add(node.name);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const referenced = new Set();
|
|
290
|
+
if ('data' in node && isRecord(node.data) && 'estree' in node.data) {
|
|
291
|
+
collectIdentifierNames(node.data.estree, referenced);
|
|
292
|
+
}
|
|
293
|
+
if (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') {
|
|
294
|
+
for (const attribute of node.attributes) {
|
|
295
|
+
collectIdentifierNames(attribute, referenced);
|
|
296
|
+
if (attribute.type !== 'mdxJsxAttribute' || typeof attribute.value !== 'object')
|
|
297
|
+
continue;
|
|
298
|
+
const stubName = extractIdentifierRef((_c = (_b = (_a = attribute.value) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.estree) !== null && _c !== void 0 ? _c : undefined);
|
|
299
|
+
if (stubName)
|
|
300
|
+
attributeStubNames.add(stubName);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
for (const name of referenced) {
|
|
304
|
+
if (candidates.has(name))
|
|
305
|
+
rejected.add(name);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
return { rejected, attributeStubNames };
|
|
309
|
+
}
|
|
310
|
+
function isConstantReference(program, constantNames) {
|
|
311
|
+
const statement = program === null || program === void 0 ? void 0 : program.body[0];
|
|
312
|
+
if ((program === null || program === void 0 ? void 0 : program.body.length) !== 1 || (statement === null || statement === void 0 ? void 0 : statement.type) !== 'ExpressionStatement')
|
|
313
|
+
return false;
|
|
314
|
+
return statement.expression.type === 'Identifier' && constantNames.has(statement.expression.name);
|
|
315
|
+
}
|
|
316
|
+
// Returns the identifier name if the estree expression is a bare reference that will be kept
|
|
317
|
+
// by isStringSafe but needs a stub to avoid a ReferenceError at render time:
|
|
318
|
+
// {foo} → Identifier
|
|
319
|
+
// {!!foo} → UnaryExpression(! UnaryExpression(! Identifier))
|
|
320
|
+
// Parenthesised forms are transparent in ESTree so (foo) produces the same AST as foo.
|
|
321
|
+
export function extractIdentifierRef(estree) {
|
|
322
|
+
const stmt = estree === null || estree === void 0 ? void 0 : estree.body[0];
|
|
323
|
+
if ((stmt === null || stmt === void 0 ? void 0 : stmt.type) !== 'ExpressionStatement')
|
|
324
|
+
return null;
|
|
325
|
+
const expr = stmt.expression;
|
|
326
|
+
if (expr.type === 'Identifier')
|
|
327
|
+
return expr.name;
|
|
328
|
+
if (expr.type === 'UnaryExpression' &&
|
|
329
|
+
expr.operator === '!' &&
|
|
330
|
+
expr.argument.type === 'UnaryExpression' &&
|
|
331
|
+
expr.argument.operator === '!' &&
|
|
332
|
+
expr.argument.argument.type === 'Identifier')
|
|
333
|
+
return expr.argument.argument.name;
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
function usesOnlyUnshadowedBuiltIns(statement, shadowing) {
|
|
337
|
+
const elementNames = new Set();
|
|
338
|
+
collectJsxElementNames(statement, elementNames);
|
|
339
|
+
for (const name of elementNames) {
|
|
340
|
+
if (/^[A-Z]/.test(name) && shadowing.has(name))
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
function collectTopLevelBindings(program, out) {
|
|
346
|
+
for (const statement of program.body) {
|
|
347
|
+
if (statement.type === 'ImportDeclaration') {
|
|
348
|
+
for (const specifier of statement.specifiers)
|
|
349
|
+
out.add(specifier.local.name);
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
if ((statement.type !== 'ExportNamedDeclaration' &&
|
|
353
|
+
statement.type !== 'ExportDefaultDeclaration') ||
|
|
354
|
+
!statement.declaration) {
|
|
355
|
+
collectIdentifierNames(statement, out, ['Identifier']);
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
const declaration = statement.declaration;
|
|
359
|
+
if ((declaration === null || declaration === void 0 ? void 0 : declaration.type) === 'VariableDeclaration') {
|
|
360
|
+
for (const declarator of declaration.declarations) {
|
|
361
|
+
collectIdentifierNames(declarator.id, out, ['Identifier']);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
else if (((declaration === null || declaration === void 0 ? void 0 : declaration.type) === 'FunctionDeclaration' || (declaration === null || declaration === void 0 ? void 0 : declaration.type) === 'ClassDeclaration') &&
|
|
365
|
+
declaration.id) {
|
|
366
|
+
out.add(declaration.id.name);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function collectIdentifierNames(value, out, types = ['Identifier', 'JSXIdentifier']) {
|
|
371
|
+
walkEstree(value, (node) => {
|
|
372
|
+
if (typeof node.type === 'string' &&
|
|
373
|
+
types.includes(node.type) &&
|
|
374
|
+
typeof node.name === 'string') {
|
|
375
|
+
out.add(node.name);
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
function collectJsxElementNames(value, out) {
|
|
380
|
+
walkEstree(value, (node) => {
|
|
381
|
+
if (node.type !== 'JSXOpeningElement' || !('name' in node) || !isRecord(node.name))
|
|
382
|
+
return;
|
|
383
|
+
if (node.name.type === 'JSXIdentifier' && typeof node.name.name === 'string') {
|
|
384
|
+
out.add(node.name.name);
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
function walkEstree(value, onNode) {
|
|
389
|
+
if (Array.isArray(value)) {
|
|
390
|
+
for (const item of value)
|
|
391
|
+
walkEstree(item, onNode);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
if (!isRecord(value))
|
|
395
|
+
return;
|
|
396
|
+
if (typeof value.type === 'string')
|
|
397
|
+
onNode(value);
|
|
398
|
+
for (const [key, child] of Object.entries(value)) {
|
|
399
|
+
if (key === 'loc' || key === 'range' || key === 'position')
|
|
400
|
+
continue;
|
|
401
|
+
walkEstree(child, onNode);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
function isRecord(value) {
|
|
405
|
+
return typeof value === 'object' && value !== null;
|
|
406
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { jsx as jsxHandlers, toJs } from 'estree-util-to-js';
|
|
1
2
|
import { remove } from 'unist-util-remove';
|
|
2
3
|
import { CONTINUE, visit } from 'unist-util-visit';
|
|
3
4
|
import { UNSAFE_OBJECT_KEYS } from '../../static-object-keys.js';
|
|
4
5
|
import { isMdxJsEsm } from '../../utils.js';
|
|
6
|
+
import { extractIdentifierRef, getKeptEsmStatements } from './pureTemplateComponents.js';
|
|
5
7
|
const objectEstree = {
|
|
6
8
|
type: 'Program',
|
|
7
9
|
body: [
|
|
@@ -402,26 +404,6 @@ function collectIdentifiersFromPattern(pattern, out) {
|
|
|
402
404
|
collectIdentifiersFromPattern(pattern.argument, out);
|
|
403
405
|
}
|
|
404
406
|
}
|
|
405
|
-
// Returns the identifier name if the estree expression is a bare reference that will be kept
|
|
406
|
-
// by isStringSafe but needs a stub to avoid a ReferenceError at render time:
|
|
407
|
-
// {foo} → Identifier
|
|
408
|
-
// {!!foo} → UnaryExpression(! UnaryExpression(! Identifier))
|
|
409
|
-
// Parenthesised forms are transparent in ESTree so (foo) produces the same AST as foo.
|
|
410
|
-
function extractIdentifierRef(estree) {
|
|
411
|
-
const stmt = estree === null || estree === void 0 ? void 0 : estree.body[0];
|
|
412
|
-
if ((stmt === null || stmt === void 0 ? void 0 : stmt.type) !== 'ExpressionStatement')
|
|
413
|
-
return null;
|
|
414
|
-
const expr = stmt.expression;
|
|
415
|
-
if (expr.type === 'Identifier')
|
|
416
|
-
return expr.name;
|
|
417
|
-
if (expr.type === 'UnaryExpression' &&
|
|
418
|
-
expr.operator === '!' &&
|
|
419
|
-
expr.argument.type === 'UnaryExpression' &&
|
|
420
|
-
expr.argument.operator === '!' &&
|
|
421
|
-
expr.argument.argument.type === 'Identifier')
|
|
422
|
-
return expr.argument.argument.name;
|
|
423
|
-
return null;
|
|
424
|
-
}
|
|
425
407
|
function collectExportedNames(estree) {
|
|
426
408
|
var _a, _b;
|
|
427
409
|
const names = [];
|
|
@@ -690,19 +672,43 @@ function sanitizer(edit) {
|
|
|
690
672
|
});
|
|
691
673
|
}
|
|
692
674
|
edit.remove(tree, (node) => isMdxExpression(node) && !isInertExpression(node));
|
|
675
|
+
const keptStatements = getKeptEsmStatements(tree);
|
|
676
|
+
const keptNames = new Set(collectExportedNames({
|
|
677
|
+
type: 'Program',
|
|
678
|
+
body: [...keptStatements],
|
|
679
|
+
sourceType: 'module',
|
|
680
|
+
}).map(({ name }) => name));
|
|
693
681
|
// Collect exported names before stripping ESM so we can inject stubs.
|
|
694
682
|
// Map keyed by name deduplicates naturally.
|
|
695
683
|
const stubbedNamesMap = new Map();
|
|
696
|
-
|
|
684
|
+
const partiallyKept = [];
|
|
685
|
+
visit(tree, (node, index, parent) => {
|
|
697
686
|
var _a;
|
|
698
|
-
if (isMdxJsEsm(node)
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
687
|
+
if (!isMdxJsEsm(node) || !((_a = node.data) === null || _a === void 0 ? void 0 : _a.estree))
|
|
688
|
+
return;
|
|
689
|
+
const program = node.data.estree;
|
|
690
|
+
const stripped = program.body.filter((statement) => !keptStatements.has(statement));
|
|
691
|
+
for (const entry of collectExportedNames(Object.assign(Object.assign({}, program), { body: stripped }))) {
|
|
692
|
+
if (!stubbedNamesMap.has(entry.name))
|
|
693
|
+
stubbedNamesMap.set(entry.name, entry);
|
|
694
|
+
}
|
|
695
|
+
if (stripped.length > 0 && stripped.length < program.body.length && parent && index != null) {
|
|
696
|
+
const body = program.body.filter((statement) => keptStatements.has(statement));
|
|
697
|
+
partiallyKept.push({ parent, index, program: Object.assign(Object.assign({}, program), { body, comments: [] }) });
|
|
703
698
|
}
|
|
704
699
|
});
|
|
705
|
-
|
|
700
|
+
for (const { parent, index, program } of partiallyKept) {
|
|
701
|
+
edit.replaceChild(parent, index, {
|
|
702
|
+
type: 'mdxjsEsm',
|
|
703
|
+
value: toJs(program, { handlers: jsxHandlers }).value,
|
|
704
|
+
data: { estree: program },
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
edit.remove(tree, (node) => {
|
|
708
|
+
var _a, _b;
|
|
709
|
+
return isMdxJsEsm(node) &&
|
|
710
|
+
!((_b = (_a = node.data) === null || _a === void 0 ? void 0 : _a.estree) === null || _b === void 0 ? void 0 : _b.body.some((statement) => keptStatements.has(statement)));
|
|
711
|
+
});
|
|
706
712
|
// Sanitize JSX attributes. Any bare identifier that survives is added to stubbedNamesMap
|
|
707
713
|
// so it gets a stub even if its import was already stripped by a prior plugin.
|
|
708
714
|
visit(tree, (node) => {
|
|
@@ -717,7 +723,7 @@ function sanitizer(edit) {
|
|
|
717
723
|
if (attr.type === 'mdxJsxAttribute' && attr.value instanceof Object) {
|
|
718
724
|
if (isStringSafe(attr.value.value)) {
|
|
719
725
|
const ident = extractIdentifierRef((_a = attr.value.data) === null || _a === void 0 ? void 0 : _a.estree);
|
|
720
|
-
if (ident && !stubbedNamesMap.has(ident))
|
|
726
|
+
if (ident && !stubbedNamesMap.has(ident) && !keptNames.has(ident))
|
|
721
727
|
stubbedNamesMap.set(ident, { name: ident, isFunction: false });
|
|
722
728
|
return attr;
|
|
723
729
|
}
|