@mintlify/common 1.0.1258 → 1.0.1259

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.
@@ -2,93 +2,438 @@ import { walk } from 'estree-walker';
2
2
  import { visit } from 'unist-util-visit';
3
3
  import { segment } from './segment.js';
4
4
  export const MINTLIFY_TAILWIND_PREFIX = 'mint-';
5
+ const CLASS_HELPERS = new Set(['cn', 'clsx', 'classNames', 'classnames', 'twMerge', 'twJoin']);
5
6
  export const rehypeDynamicTailwindCss = (tailwindSelectors) => (tree) => {
6
7
  const normalizedTailwindSelectors = tailwindSelectors === null || tailwindSelectors === void 0 ? void 0 : tailwindSelectors.map(normalizeSelector);
8
+ if (!(normalizedTailwindSelectors === null || normalizedTailwindSelectors === void 0 ? void 0 : normalizedTailwindSelectors.length))
9
+ return;
10
+ const moduleScope = new Map();
11
+ const moduleScopes = [moduleScope];
12
+ visit(tree, (node) => {
13
+ if (node.type === 'mdxjsEsm' && node.data && node.data.estree) {
14
+ collectDeclarations(node.data.estree.body, moduleScope, moduleScopes);
15
+ }
16
+ });
7
17
  visit(tree, (node) => {
18
+ var _a;
8
19
  if ((node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') &&
9
20
  node.name &&
10
21
  typeof node.name === 'string' &&
11
22
  node.attributes.length > 0) {
12
- const className = node.attributes.find((attr) => attr.type === 'mdxJsxAttribute' && attr.name === 'className');
13
- if (className && typeof className.value === 'string') {
14
- className.value = transformClassNames(className.value, normalizedTailwindSelectors);
23
+ const className = node.attributes.find((attr) => attr.type === 'mdxJsxAttribute' && (attr.name === 'className' || attr.name === 'class'));
24
+ const value = className === null || className === void 0 ? void 0 : className.value;
25
+ if (className && typeof value === 'string') {
26
+ className.value = transformClassNames(value, normalizedTailwindSelectors);
27
+ }
28
+ else if (value && typeof value !== 'string' && ((_a = value.data) === null || _a === void 0 ? void 0 : _a.estree)) {
29
+ // example: <div className={isActive ? "bg-red-500" : "bg-blue-500"}>
30
+ const [statement] = value.data.estree.body;
31
+ if (statement && statement.type === 'ExpressionStatement') {
32
+ statement.expression = transformExpressionClassNames(statement.expression, moduleScopes, normalizedTailwindSelectors);
33
+ }
15
34
  }
16
35
  }
17
36
  if (node.type === 'mdxjsEsm' && node.data && node.data.estree) {
18
- transformMdxJsEsmNode(node.data.estree, normalizedTailwindSelectors);
37
+ transformMdxJsEsmNode(node.data.estree, moduleScopes, normalizedTailwindSelectors);
19
38
  }
20
39
  });
21
40
  };
22
- const transformMdxJsEsmNode = (estreeNode, tailwindSelectors) => {
41
+ const collectDeclarations = (statements, scope, scopes) => {
42
+ for (const statement of statements) {
43
+ const declaration = statement.type === 'ExportNamedDeclaration' ? statement.declaration : statement;
44
+ if ((declaration === null || declaration === void 0 ? void 0 : declaration.type) === 'FunctionDeclaration' && declaration.id) {
45
+ scope.set(declaration.id.name, { scopes });
46
+ }
47
+ if ((declaration === null || declaration === void 0 ? void 0 : declaration.type) !== 'VariableDeclaration')
48
+ continue;
49
+ for (const declarator of declaration.declarations) {
50
+ if (declaration.kind === 'const' && declarator.id.type === 'Identifier' && declarator.init) {
51
+ scope.set(declarator.id.name, { init: declarator.init, scopes });
52
+ }
53
+ else {
54
+ getPatternNames(declarator.id).forEach((name) => scope.set(name, { scopes }));
55
+ }
56
+ }
57
+ }
58
+ };
59
+ const getPatternNames = (pattern) => {
60
+ switch (pattern.type) {
61
+ case 'Identifier':
62
+ return [pattern.name];
63
+ case 'AssignmentPattern':
64
+ return getPatternNames(pattern.left);
65
+ case 'RestElement':
66
+ return getPatternNames(pattern.argument);
67
+ case 'ArrayPattern':
68
+ return pattern.elements.flatMap((element) => (element ? getPatternNames(element) : []));
69
+ case 'ObjectPattern':
70
+ return pattern.properties.flatMap((property) => getPatternNames(property.type === 'Property' ? property.value : property));
71
+ default:
72
+ return [];
73
+ }
74
+ };
75
+ const resolveBinding = (name, scopes) => {
76
+ var _a;
77
+ for (let i = scopes.length - 1; i >= 0; i--) {
78
+ const binding = (_a = scopes[i]) === null || _a === void 0 ? void 0 : _a.get(name);
79
+ if (binding)
80
+ return binding;
81
+ }
82
+ return undefined;
83
+ };
84
+ const isFunctionNode = (node) => node.type === 'FunctionDeclaration' ||
85
+ node.type === 'FunctionExpression' ||
86
+ node.type === 'ArrowFunctionExpression';
87
+ const transformMdxJsEsmNode = (estreeNode, moduleScopes, tailwindSelectors) => {
88
+ const scopes = [...moduleScopes];
23
89
  walk(estreeNode, {
24
90
  enter(node) {
91
+ if (isFunctionNode(node)) {
92
+ const scope = new Map();
93
+ const chain = [...scopes, scope];
94
+ node.params.flatMap(getPatternNames).forEach((name) => scope.set(name, { scopes: chain }));
95
+ scopes.push(scope);
96
+ return;
97
+ }
98
+ if (node.type === 'BlockStatement') {
99
+ const scope = new Map();
100
+ collectDeclarations(node.body, scope, [...scopes, scope]);
101
+ scopes.push(scope);
102
+ return;
103
+ }
25
104
  if (node.type === 'JSXAttribute' &&
26
105
  node.name.type === 'JSXIdentifier' &&
27
106
  (node.name.name === 'className' || node.name.name === 'class')) {
28
- if (node.value && node.value.type === 'JSXExpressionContainer') {
29
- const expression = node.value.expression;
30
- if (expression.type === 'TemplateLiteral') {
31
- // example: className={`bg-green-500`}
32
- expression.quasis.forEach((quasi) => {
33
- if (quasi.value.cooked) {
34
- const originalValue = quasi.value.cooked;
35
- const transformedValue = transformClassNames(originalValue, tailwindSelectors);
36
- if (originalValue !== transformedValue) {
37
- quasi.value.cooked = transformedValue;
38
- quasi.value.raw = transformedValue;
39
- }
40
- }
41
- });
42
- // example: className={`${isActive ? "bg-red-500" : "bg-blue-500"}`}
43
- expression.expressions.forEach((expr) => {
44
- transformExpressionClassNames(expr, tailwindSelectors);
45
- });
46
- }
47
- }
48
107
  // example: className="bg-green-500"
49
- if (node.value && node.value.type === 'Literal' && typeof node.value.value === 'string') {
50
- const originalValue = node.value.value;
51
- const transformedValue = transformClassNames(originalValue, tailwindSelectors);
52
- if (originalValue !== transformedValue) {
53
- node.value.value = transformedValue;
54
- if (typeof node.value.raw === 'string') {
55
- node.value.raw = JSON.stringify(transformedValue);
56
- }
57
- }
108
+ if (node.value && node.value.type === 'Literal') {
109
+ transformLiteral(node.value, tailwindSelectors);
110
+ }
111
+ if (node.value &&
112
+ node.value.type === 'JSXExpressionContainer' &&
113
+ node.value.expression.type !== 'JSXEmptyExpression') {
114
+ node.value.expression = transformExpressionClassNames(node.value.expression, scopes, tailwindSelectors);
58
115
  }
59
116
  }
60
117
  },
118
+ leave(node) {
119
+ if (node.type === 'BlockStatement' || isFunctionNode(node)) {
120
+ scopes.pop();
121
+ }
122
+ },
61
123
  });
62
124
  };
63
- const transformExpressionClassNames = (expr, tailwindSelectors) => {
64
- if (!expr)
65
- return;
66
- if (expr.type === 'Literal' && typeof expr.value === 'string') {
67
- const originalValue = expr.value;
68
- const transformedValue = transformClassNames(originalValue, tailwindSelectors);
69
- if (originalValue !== transformedValue) {
70
- expr.value = transformedValue;
71
- if (typeof expr.raw === 'string') {
72
- expr.raw = JSON.stringify(transformedValue);
125
+ const transformExpressionClassNames = (expr, scopes, tailwindSelectors, inlining = new Set()) => {
126
+ const transform = (child) => transformExpressionClassNames(child, scopes, tailwindSelectors, inlining);
127
+ const transformElement = (element) => {
128
+ if (element.type !== 'SpreadElement')
129
+ return transform(element);
130
+ element.argument = transform(element.argument);
131
+ return element;
132
+ };
133
+ switch (expr.type) {
134
+ case 'Literal':
135
+ transformLiteral(expr, tailwindSelectors);
136
+ return expr;
137
+ case 'TemplateLiteral':
138
+ // example: className={`bg-green-500`}
139
+ expr.quasis.forEach((quasi) => {
140
+ if (quasi.value.cooked) {
141
+ const transformedValue = transformClassNames(quasi.value.cooked, tailwindSelectors);
142
+ if (quasi.value.cooked !== transformedValue) {
143
+ quasi.value.cooked = transformedValue;
144
+ quasi.value.raw = transformedValue;
145
+ }
146
+ }
147
+ });
148
+ // example: className={`${isActive ? "bg-red-500" : "bg-blue-500"}`}
149
+ expr.expressions = expr.expressions.map(transform);
150
+ return expr;
151
+ case 'ConditionalExpression':
152
+ // example: ${isActive ? "bg-red-500" : "bg-blue-500"}
153
+ expr.consequent = transform(expr.consequent);
154
+ expr.alternate = transform(expr.alternate);
155
+ return expr;
156
+ case 'LogicalExpression':
157
+ // example: ${isActive && "bg-red-500"}
158
+ expr.left = transform(expr.left);
159
+ expr.right = transform(expr.right);
160
+ return expr;
161
+ case 'BinaryExpression':
162
+ if (expr.operator === '+') {
163
+ // example: ${"bg-red-500" + "bg-blue-500"}
164
+ expr.left = transform(expr.left);
165
+ expr.right = transform(expr.right);
166
+ }
167
+ return expr;
168
+ case 'ArrayExpression':
169
+ // example: ["bg-red-500", "bg-blue-500"]
170
+ expr.elements = expr.elements.map((element) => element && transformElement(element));
171
+ return expr;
172
+ case 'CallExpression':
173
+ if (!isClassCall(expr))
174
+ return expr;
175
+ // example: ["bg-red-500", "bg-blue-500"].join(" ")
176
+ if (expr.callee.type === 'MemberExpression' && expr.callee.object.type !== 'Super') {
177
+ expr.callee.object = transform(expr.callee.object);
178
+ }
179
+ expr.arguments = expr.arguments.map(transformElement);
180
+ return expr;
181
+ case 'ObjectExpression':
182
+ // example: cn({ "bg-blue-500": isActive })
183
+ transformObjectKeys(expr, transform, tailwindSelectors);
184
+ return expr;
185
+ case 'MemberExpression':
186
+ // example: const styles = { active: "bg-red-500" }; className={styles.active}
187
+ return transformMemberExpression(expr, scopes, transform);
188
+ case 'Identifier': {
189
+ // example: const classes = "bg-red-500"; className={classes}
190
+ const binding = resolveBinding(expr.name, scopes);
191
+ if (!(binding === null || binding === void 0 ? void 0 : binding.init) || inlining.has(binding))
192
+ return expr;
193
+ const inlined = cloneForUse(binding.init, binding.scopes, scopes, new Set([binding]));
194
+ if (!inlined)
195
+ return expr;
196
+ const before = serialize(inlined);
197
+ const transformed = transformExpressionClassNames(inlined, scopes, tailwindSelectors, new Set([...inlining, binding]));
198
+ return serialize(transformed) === before ? expr : transformed;
199
+ }
200
+ default:
201
+ return expr;
202
+ }
203
+ };
204
+ const transformMemberExpression = (expr, scopes, transform) => {
205
+ if (getStaticKey(expr) !== undefined) {
206
+ const resolved = resolveStaticValue(expr, scopes);
207
+ const inlined = resolved && cloneForUse(resolved.expr, resolved.scopes, scopes, new Set());
208
+ if (!inlined)
209
+ return expr;
210
+ const before = serialize(inlined);
211
+ const transformed = transform(inlined);
212
+ return serialize(transformed) === before ? expr : transformed;
213
+ }
214
+ const object = resolveObject(expr.object, scopes);
215
+ if (!object)
216
+ return expr;
217
+ const before = serialize(object);
218
+ object.properties.forEach((property) => {
219
+ const value = property.type === 'Property' ? asExpression(property.value) : undefined;
220
+ if (property.type === 'Property' && value)
221
+ property.value = transform(value);
222
+ });
223
+ if (serialize(object) !== before)
224
+ expr.object = object;
225
+ return expr;
226
+ };
227
+ const transformObjectKeys = (expr, transform, tailwindSelectors) => {
228
+ expr.properties.forEach((property) => {
229
+ if (property.type === 'SpreadElement') {
230
+ property.argument = transform(property.argument);
231
+ return;
232
+ }
233
+ if (property.computed) {
234
+ if (property.key.type !== 'PrivateIdentifier')
235
+ property.key = transform(property.key);
236
+ return;
237
+ }
238
+ const keyName = getPropertyKeyName(property);
239
+ if (keyName === undefined)
240
+ return;
241
+ const transformedValue = transformClassNames(keyName, tailwindSelectors);
242
+ if (keyName !== transformedValue) {
243
+ property.key = toLiteral(transformedValue);
244
+ property.shorthand = false;
245
+ }
246
+ });
247
+ };
248
+ const resolveObject = (node, scopes) => {
249
+ if (node.type === 'ObjectExpression')
250
+ return node;
251
+ const resolved = resolveStaticValue(node, scopes);
252
+ if ((resolved === null || resolved === void 0 ? void 0 : resolved.expr.type) !== 'ObjectExpression')
253
+ return undefined;
254
+ const cloned = cloneForUse(resolved.expr, resolved.scopes, scopes, new Set());
255
+ return (cloned === null || cloned === void 0 ? void 0 : cloned.type) === 'ObjectExpression' ? cloned : undefined;
256
+ };
257
+ const resolveStaticValue = (node, scopes, resolving = new Set()) => {
258
+ if (node.type === 'Super')
259
+ return undefined;
260
+ if (node.type === 'Identifier') {
261
+ const binding = resolveBinding(node.name, scopes);
262
+ if (!(binding === null || binding === void 0 ? void 0 : binding.init))
263
+ return { expr: node, scopes };
264
+ if (resolving.has(binding))
265
+ return undefined;
266
+ return resolveStaticValue(binding.init, binding.scopes, new Set([...resolving, binding]));
267
+ }
268
+ if (node.type === 'MemberExpression') {
269
+ const key = getStaticKey(node);
270
+ if (key === undefined)
271
+ return { expr: node, scopes };
272
+ const object = resolveStaticValue(node.object, scopes, resolving);
273
+ if ((object === null || object === void 0 ? void 0 : object.expr.type) !== 'ObjectExpression')
274
+ return undefined;
275
+ const value = findPropertyValue(object.expr, key);
276
+ return value && resolveStaticValue(value, object.scopes, resolving);
277
+ }
278
+ return { expr: node, scopes };
279
+ };
280
+ const cloneForUse = (expr, declarationScopes, useScopes, inlining) => {
281
+ const clone = (child) => cloneForUse(child, declarationScopes, useScopes, inlining);
282
+ const cloneElement = (element) => {
283
+ if (element.type !== 'SpreadElement')
284
+ return clone(element);
285
+ const argument = clone(element.argument);
286
+ return argument && Object.assign(Object.assign({}, element), { argument });
287
+ };
288
+ const cloneAll = (items, cloneItem) => {
289
+ const cloned = [];
290
+ for (const item of items) {
291
+ const result = cloneItem(item);
292
+ if (result === undefined)
293
+ return undefined;
294
+ cloned.push(result);
295
+ }
296
+ return cloned;
297
+ };
298
+ switch (expr.type) {
299
+ case 'Literal':
300
+ return structuredClone(expr);
301
+ case 'TemplateLiteral': {
302
+ const expressions = cloneAll(expr.expressions, clone);
303
+ return expressions && Object.assign(Object.assign({}, expr), { quasis: structuredClone(expr.quasis), expressions });
304
+ }
305
+ case 'ArrayExpression': {
306
+ const elements = cloneAll(expr.elements, (element) => element === null ? null : cloneElement(element));
307
+ return elements && Object.assign(Object.assign({}, expr), { elements });
308
+ }
309
+ case 'BinaryExpression': {
310
+ const left = clone(expr.left);
311
+ const right = clone(expr.right);
312
+ return left && right && Object.assign(Object.assign({}, expr), { left, right });
313
+ }
314
+ case 'LogicalExpression': {
315
+ const left = clone(expr.left);
316
+ const right = clone(expr.right);
317
+ return left && right && Object.assign(Object.assign({}, expr), { left, right });
318
+ }
319
+ case 'ConditionalExpression': {
320
+ const test = clone(expr.test);
321
+ const consequent = clone(expr.consequent);
322
+ const alternate = clone(expr.alternate);
323
+ return test && consequent && alternate && Object.assign(Object.assign({}, expr), { test, consequent, alternate });
324
+ }
325
+ case 'UnaryExpression': {
326
+ const argument = clone(expr.argument);
327
+ return argument && Object.assign(Object.assign({}, expr), { argument });
328
+ }
329
+ case 'ObjectExpression': {
330
+ const properties = cloneAll(expr.properties, (property) => {
331
+ if (property.type === 'SpreadElement') {
332
+ const argument = clone(property.argument);
333
+ return argument && Object.assign(Object.assign({}, property), { argument });
334
+ }
335
+ if (property.kind !== 'init' || property.method)
336
+ return undefined;
337
+ const value = asExpression(property.value);
338
+ const clonedValue = value && clone(value);
339
+ if (!clonedValue)
340
+ return undefined;
341
+ if (!property.computed) {
342
+ return Object.assign(Object.assign({}, property), { key: structuredClone(property.key), value: clonedValue, shorthand: false });
343
+ }
344
+ if (property.key.type === 'PrivateIdentifier')
345
+ return undefined;
346
+ const key = clone(property.key);
347
+ return key && Object.assign(Object.assign({}, property), { key, value: clonedValue, shorthand: false });
348
+ });
349
+ return properties && Object.assign(Object.assign({}, expr), { properties });
350
+ }
351
+ case 'MemberExpression': {
352
+ if (expr.object.type === 'Super' || expr.property.type === 'PrivateIdentifier') {
353
+ return undefined;
354
+ }
355
+ const object = clone(expr.object);
356
+ const property = expr.computed ? clone(expr.property) : structuredClone(expr.property);
357
+ return object && property && Object.assign(Object.assign({}, expr), { object, property });
358
+ }
359
+ case 'CallExpression': {
360
+ if (!isClassCall(expr) || expr.callee.type === 'Super')
361
+ return undefined;
362
+ const callee = clone(expr.callee);
363
+ const args = cloneAll(expr.arguments, cloneElement);
364
+ return callee && args && Object.assign(Object.assign({}, expr), { callee, arguments: args });
365
+ }
366
+ case 'Identifier': {
367
+ const binding = resolveBinding(expr.name, declarationScopes);
368
+ if ((binding === null || binding === void 0 ? void 0 : binding.init) && !inlining.has(binding)) {
369
+ const inlined = cloneForUse(binding.init, binding.scopes, useScopes, new Set([...inlining, binding]));
370
+ if (inlined)
371
+ return inlined;
73
372
  }
373
+ return binding === resolveBinding(expr.name, useScopes) ? structuredClone(expr) : undefined;
74
374
  }
375
+ default:
376
+ return undefined;
75
377
  }
76
- else if (expr.type === 'ConditionalExpression') {
77
- // example: ${isActive ? "bg-red-500" : "bg-blue-500"}
78
- transformExpressionClassNames(expr.consequent, tailwindSelectors);
79
- transformExpressionClassNames(expr.alternate, tailwindSelectors);
378
+ };
379
+ const isClassCall = (expr) => {
380
+ const { callee } = expr;
381
+ if (callee.type === 'Identifier')
382
+ return CLASS_HELPERS.has(callee.name);
383
+ return (callee.type === 'MemberExpression' &&
384
+ !callee.computed &&
385
+ callee.property.type === 'Identifier' &&
386
+ (callee.property.name === 'join' || callee.property.name === 'concat'));
387
+ };
388
+ const getStaticKey = (expr) => {
389
+ if (!expr.computed && expr.property.type === 'Identifier')
390
+ return expr.property.name;
391
+ if (expr.property.type === 'Literal' && typeof expr.property.value === 'string') {
392
+ return expr.property.value;
393
+ }
394
+ return undefined;
395
+ };
396
+ const getPropertyKeyName = (property) => {
397
+ if (!property.computed && property.key.type === 'Identifier')
398
+ return property.key.name;
399
+ if (property.key.type === 'Literal' && typeof property.key.value === 'string') {
400
+ return property.key.value;
80
401
  }
81
- else if (expr.type === 'LogicalExpression') {
82
- // example: ${isActive && "bg-red-500"}
83
- transformExpressionClassNames(expr.left, tailwindSelectors);
84
- transformExpressionClassNames(expr.right, tailwindSelectors);
402
+ return undefined;
403
+ };
404
+ const findPropertyValue = (object, key) => {
405
+ for (let i = object.properties.length - 1; i >= 0; i--) {
406
+ const property = object.properties[i];
407
+ if (!property || property.type === 'SpreadElement')
408
+ return undefined;
409
+ if (getPropertyKeyName(property) === key)
410
+ return asExpression(property.value);
85
411
  }
86
- else if (expr.type === 'BinaryExpression' && expr.operator === '+') {
87
- // example: ${"bg-red-500" + "bg-blue-500"}
88
- transformExpressionClassNames(expr.left, tailwindSelectors);
89
- transformExpressionClassNames(expr.right, tailwindSelectors);
412
+ return undefined;
413
+ };
414
+ const asExpression = (node) => node.type === 'ObjectPattern' ||
415
+ node.type === 'ArrayPattern' ||
416
+ node.type === 'RestElement' ||
417
+ node.type === 'AssignmentPattern'
418
+ ? undefined
419
+ : node;
420
+ const transformLiteral = (expr, tailwindSelectors) => {
421
+ if (typeof expr.value !== 'string')
422
+ return;
423
+ const transformedValue = transformClassNames(expr.value, tailwindSelectors);
424
+ if (expr.value !== transformedValue) {
425
+ expr.value = transformedValue;
426
+ if (typeof expr.raw === 'string') {
427
+ expr.raw = JSON.stringify(transformedValue);
428
+ }
90
429
  }
91
430
  };
431
+ const toLiteral = (value) => ({
432
+ type: 'Literal',
433
+ value,
434
+ raw: JSON.stringify(value),
435
+ });
436
+ const serialize = (node) => JSON.stringify(node, (_key, value) => typeof value === 'bigint' ? value.toString() : value);
92
437
  const transformClassNames = (value, tailwindSelectors) => {
93
438
  var _a, _b, _c, _d;
94
439
  if (!tailwindSelectors || !tailwindSelectors.length)