@mintlify/common 1.0.1259 → 1.0.1260

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.
@@ -3,17 +3,76 @@ import { visit } from 'unist-util-visit';
3
3
  import { segment } from './segment.js';
4
4
  export const MINTLIFY_TAILWIND_PREFIX = 'mint-';
5
5
  const CLASS_HELPERS = new Set(['cn', 'clsx', 'classNames', 'classnames', 'twMerge', 'twJoin']);
6
+ const NON_MUTATING_METHODS = new Set([
7
+ 'at',
8
+ 'charAt',
9
+ 'concat',
10
+ 'endsWith',
11
+ 'includes',
12
+ 'indexOf',
13
+ 'join',
14
+ 'lastIndexOf',
15
+ 'padEnd',
16
+ 'padStart',
17
+ 'repeat',
18
+ 'slice',
19
+ 'split',
20
+ 'startsWith',
21
+ 'toLowerCase',
22
+ 'toString',
23
+ 'toUpperCase',
24
+ 'trim',
25
+ 'trimEnd',
26
+ 'trimStart',
27
+ ]);
28
+ const IMMUTABLE_GLOBALS = new Set(['undefined', 'NaN', 'Infinity']);
29
+ const MAX_INLINE_DEPTH = 32;
30
+ const MAX_NODES_PER_INLINE = 1000;
31
+ const MAX_INLINED_NODES_PER_PAGE = 20000;
6
32
  export const rehypeDynamicTailwindCss = (tailwindSelectors) => (tree) => {
7
33
  const normalizedTailwindSelectors = tailwindSelectors === null || tailwindSelectors === void 0 ? void 0 : tailwindSelectors.map(normalizeSelector);
8
34
  if (!(normalizedTailwindSelectors === null || normalizedTailwindSelectors === void 0 ? void 0 : normalizedTailwindSelectors.length))
9
35
  return;
10
36
  const moduleScope = new Map();
11
37
  const moduleScopes = [moduleScope];
38
+ const scopeByNode = new Map();
39
+ const aliases = [];
12
40
  visit(tree, (node) => {
13
41
  if (node.type === 'mdxjsEsm' && node.data && node.data.estree) {
14
42
  collectDeclarations(node.data.estree.body, moduleScope, moduleScopes);
43
+ collectVarNames(node.data.estree).forEach((name) => moduleScope.set(name, createBinding(moduleScopes)));
15
44
  }
16
45
  });
46
+ const estrees = [];
47
+ visit(tree, (node) => {
48
+ var _a;
49
+ if (node.type === 'mdxjsEsm' ||
50
+ node.type === 'mdxFlowExpression' ||
51
+ node.type === 'mdxTextExpression') {
52
+ if ((_a = node.data) === null || _a === void 0 ? void 0 : _a.estree)
53
+ estrees.push(node.data.estree);
54
+ }
55
+ else if (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') {
56
+ node.attributes.forEach((attr) => {
57
+ var _a, _b;
58
+ const estree = attr.type === 'mdxJsxExpressionAttribute'
59
+ ? (_a = attr.data) === null || _a === void 0 ? void 0 : _a.estree
60
+ : attr.value && typeof attr.value !== 'string'
61
+ ? (_b = attr.value.data) === null || _b === void 0 ? void 0 : _b.estree
62
+ : undefined;
63
+ if (estree)
64
+ estrees.push(estree);
65
+ });
66
+ }
67
+ });
68
+ estrees.forEach((estree) => analyzeProgram(estree, moduleScopes, scopeByNode, aliases));
69
+ propagateMutations(aliases);
70
+ const context = {
71
+ tailwindSelectors: normalizedTailwindSelectors,
72
+ changes: { count: 0 },
73
+ pageBudget: { remaining: MAX_INLINED_NODES_PER_PAGE },
74
+ inlineDepth: 0,
75
+ };
17
76
  visit(tree, (node) => {
18
77
  var _a;
19
78
  if ((node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') &&
@@ -29,45 +88,77 @@ export const rehypeDynamicTailwindCss = (tailwindSelectors) => (tree) => {
29
88
  // example: <div className={isActive ? "bg-red-500" : "bg-blue-500"}>
30
89
  const [statement] = value.data.estree.body;
31
90
  if (statement && statement.type === 'ExpressionStatement') {
32
- statement.expression = transformExpressionClassNames(statement.expression, moduleScopes, normalizedTailwindSelectors);
91
+ statement.expression = transformExpressionClassNames(statement.expression, moduleScopes, context);
33
92
  }
34
93
  }
35
94
  }
36
95
  if (node.type === 'mdxjsEsm' && node.data && node.data.estree) {
37
- transformMdxJsEsmNode(node.data.estree, moduleScopes, normalizedTailwindSelectors);
96
+ transformMdxJsEsmNode(node.data.estree, moduleScopes, scopeByNode, context);
38
97
  }
39
98
  });
40
99
  };
100
+ const createBinding = (scopes, init) => ({
101
+ init,
102
+ scopes,
103
+ reassigned: false,
104
+ mutated: false,
105
+ aliasOf: [],
106
+ });
41
107
  const collectDeclarations = (statements, scope, scopes) => {
42
108
  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 });
109
+ if (statement.type === 'ImportDeclaration') {
110
+ statement.specifiers.forEach((specifier) => scope.set(specifier.local.name, createBinding(scopes)));
111
+ continue;
112
+ }
113
+ const declaration = statement.type === 'ExportNamedDeclaration' || statement.type === 'ExportDefaultDeclaration'
114
+ ? statement.declaration
115
+ : statement;
116
+ if (!declaration)
117
+ continue;
118
+ if ((declaration.type === 'FunctionDeclaration' || declaration.type === 'ClassDeclaration') &&
119
+ declaration.id) {
120
+ scope.set(declaration.id.name, createBinding(scopes));
46
121
  }
47
- if ((declaration === null || declaration === void 0 ? void 0 : declaration.type) !== 'VariableDeclaration')
122
+ if (declaration.type !== 'VariableDeclaration' || declaration.kind === 'var')
48
123
  continue;
49
124
  for (const declarator of declaration.declarations) {
50
125
  if (declaration.kind === 'const' && declarator.id.type === 'Identifier' && declarator.init) {
51
- scope.set(declarator.id.name, { init: declarator.init, scopes });
126
+ scope.set(declarator.id.name, createBinding(scopes, declarator.init));
52
127
  }
53
128
  else {
54
- getPatternNames(declarator.id).forEach((name) => scope.set(name, { scopes }));
129
+ getPatternNames(declarator.id).forEach((name) => scope.set(name, createBinding(scopes)));
55
130
  }
56
131
  }
57
132
  }
58
133
  };
59
- const getPatternNames = (pattern) => {
134
+ const collectVarNames = (root) => {
135
+ const names = [];
136
+ walk(root, {
137
+ enter(node) {
138
+ if (node !== root && isFunctionNode(node)) {
139
+ this.skip();
140
+ return;
141
+ }
142
+ if (node.type === 'VariableDeclaration' && node.kind === 'var') {
143
+ node.declarations.forEach((declarator) => names.push(...getPatternNames(declarator.id)));
144
+ }
145
+ },
146
+ });
147
+ return names;
148
+ };
149
+ const getPatternNames = (pattern) => getPatternIdentifiers(pattern).map((identifier) => identifier.name);
150
+ const getPatternIdentifiers = (pattern) => {
60
151
  switch (pattern.type) {
61
152
  case 'Identifier':
62
- return [pattern.name];
153
+ return [pattern];
63
154
  case 'AssignmentPattern':
64
- return getPatternNames(pattern.left);
155
+ return getPatternIdentifiers(pattern.left);
65
156
  case 'RestElement':
66
- return getPatternNames(pattern.argument);
157
+ return getPatternIdentifiers(pattern.argument);
67
158
  case 'ArrayPattern':
68
- return pattern.elements.flatMap((element) => (element ? getPatternNames(element) : []));
159
+ return pattern.elements.flatMap((element) => (element ? getPatternIdentifiers(element) : []));
69
160
  case 'ObjectPattern':
70
- return pattern.properties.flatMap((property) => getPatternNames(property.type === 'Property' ? property.value : property));
161
+ return pattern.properties.flatMap((property) => getPatternIdentifiers(property.type === 'Property' ? property.value : property));
71
162
  default:
72
163
  return [];
73
164
  }
@@ -84,64 +175,304 @@ const resolveBinding = (name, scopes) => {
84
175
  const isFunctionNode = (node) => node.type === 'FunctionDeclaration' ||
85
176
  node.type === 'FunctionExpression' ||
86
177
  node.type === 'ArrowFunctionExpression';
87
- const transformMdxJsEsmNode = (estreeNode, moduleScopes, tailwindSelectors) => {
178
+ const isClassAttribute = (node) => node.name.type === 'JSXIdentifier' &&
179
+ (node.name.name === 'className' || node.name.name === 'class');
180
+ const createScope = (node, scopes) => {
181
+ var _a;
182
+ const scope = new Map();
183
+ const chain = [...scopes, scope];
184
+ const declare = (name) => scope.set(name, createBinding(chain));
185
+ if (isFunctionNode(node)) {
186
+ if (node.type === 'FunctionExpression' && node.id)
187
+ declare(node.id.name);
188
+ node.params.flatMap(getPatternNames).forEach(declare);
189
+ collectVarNames(node.body).forEach(declare);
190
+ return scope;
191
+ }
192
+ switch (node.type) {
193
+ case 'BlockStatement':
194
+ case 'StaticBlock':
195
+ collectDeclarations(node.body, scope, chain);
196
+ return scope;
197
+ case 'SwitchStatement':
198
+ collectDeclarations(node.cases.flatMap((switchCase) => switchCase.consequent), scope, chain);
199
+ return scope;
200
+ case 'ForStatement':
201
+ if (((_a = node.init) === null || _a === void 0 ? void 0 : _a.type) === 'VariableDeclaration' && node.init.kind !== 'var') {
202
+ node.init.declarations.forEach((declarator) => getPatternNames(declarator.id).forEach(declare));
203
+ }
204
+ return scope;
205
+ case 'ForInStatement':
206
+ case 'ForOfStatement':
207
+ if (node.left.type === 'VariableDeclaration' && node.left.kind !== 'var') {
208
+ node.left.declarations.forEach((declarator) => getPatternNames(declarator.id).forEach(declare));
209
+ }
210
+ return scope;
211
+ case 'CatchClause':
212
+ if (node.param)
213
+ getPatternNames(node.param).forEach(declare);
214
+ return scope;
215
+ case 'ClassExpression':
216
+ if (node.id)
217
+ declare(node.id.name);
218
+ return scope;
219
+ default:
220
+ return undefined;
221
+ }
222
+ };
223
+ const propagateMutations = (aliases) => {
224
+ var _a;
225
+ const links = new Map();
226
+ const link = (from, to) => {
227
+ const targets = links.get(from);
228
+ if (targets)
229
+ targets.push(to);
230
+ else
231
+ links.set(from, [to]);
232
+ };
233
+ aliases.forEach((alias) => alias.aliasOf.forEach((source) => {
234
+ link(alias, source);
235
+ link(source, alias);
236
+ }));
237
+ const pending = [...links.keys()].filter((binding) => binding.mutated);
238
+ for (let current = pending.pop(); current; current = pending.pop()) {
239
+ for (const next of (_a = links.get(current)) !== null && _a !== void 0 ? _a : []) {
240
+ if (next.mutated)
241
+ continue;
242
+ next.mutated = true;
243
+ pending.push(next);
244
+ }
245
+ }
246
+ };
247
+ const analyzeProgram = (program, baseScopes, scopeByNode, aliases) => {
248
+ const scopes = [...baseScopes];
249
+ const ancestors = [];
250
+ const declaredIdentifiers = new Set();
251
+ const writtenIdentifiers = new Set();
252
+ const declare = (pattern) => pattern && getPatternIdentifiers(pattern).forEach((id) => declaredIdentifiers.add(id));
253
+ const write = (pattern) => getPatternIdentifiers(pattern).forEach((id) => writtenIdentifiers.add(id));
254
+ walk(program, {
255
+ enter(node, parent, key) {
256
+ const scope = createScope(node, scopes);
257
+ if (scope) {
258
+ scopes.push(scope);
259
+ scopeByNode.set(node, scope);
260
+ }
261
+ if (isFunctionNode(node)) {
262
+ if (node.type !== 'ArrowFunctionExpression')
263
+ declare(node.id);
264
+ node.params.forEach(declare);
265
+ }
266
+ else if (node.type === 'VariableDeclarator') {
267
+ declare(node.id);
268
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'VariableDeclaration' && parent.kind === 'var') {
269
+ getPatternNames(node.id).forEach((name) => {
270
+ const binding = resolveBinding(name, scopes);
271
+ if (binding)
272
+ binding.reassigned = true;
273
+ });
274
+ }
275
+ }
276
+ else if (node.type === 'CatchClause') {
277
+ declare(node.param);
278
+ }
279
+ else if ((node.type === 'ClassDeclaration' || node.type === 'ClassExpression') && node.id) {
280
+ declare(node.id);
281
+ }
282
+ else if (node.type === 'ImportDeclaration') {
283
+ node.specifiers.forEach((specifier) => declare(specifier.local));
284
+ }
285
+ else if (node.type === 'AssignmentExpression') {
286
+ write(node.left);
287
+ }
288
+ else if (node.type === 'UpdateExpression' && node.argument.type === 'Identifier') {
289
+ writtenIdentifiers.add(node.argument);
290
+ }
291
+ else if ((node.type === 'ForInStatement' || node.type === 'ForOfStatement') &&
292
+ node.left.type !== 'VariableDeclaration') {
293
+ write(node.left);
294
+ }
295
+ if (node.type === 'Identifier' && !declaredIdentifiers.has(node)) {
296
+ const binding = resolveBinding(node.name, scopes);
297
+ if (writtenIdentifiers.has(node)) {
298
+ if (binding)
299
+ binding.reassigned = true;
300
+ }
301
+ else if (parent && isReferencePosition(parent, key)) {
302
+ const usage = classifyReference(node, ancestors, scopes);
303
+ if (usage === 'mutates') {
304
+ if (binding)
305
+ binding.mutated = true;
306
+ }
307
+ else if (usage !== 'reads' && binding) {
308
+ usage.aliasOf.push(binding);
309
+ aliases.push(usage);
310
+ }
311
+ }
312
+ }
313
+ ancestors.push(node);
314
+ },
315
+ leave(node) {
316
+ ancestors.pop();
317
+ if (scopeByNode.has(node) && scopes[scopes.length - 1] === scopeByNode.get(node)) {
318
+ scopes.pop();
319
+ }
320
+ },
321
+ });
322
+ };
323
+ const isReferencePosition = (parent, key) => {
324
+ switch (parent.type) {
325
+ case 'MemberExpression':
326
+ return key !== 'property' || parent.computed;
327
+ case 'Property':
328
+ case 'MethodDefinition':
329
+ case 'PropertyDefinition':
330
+ return key !== 'key' || parent.computed;
331
+ case 'LabeledStatement':
332
+ case 'BreakStatement':
333
+ case 'ContinueStatement':
334
+ case 'MetaProperty':
335
+ return false;
336
+ case 'ExportSpecifier':
337
+ return key === 'local';
338
+ case 'ImportSpecifier':
339
+ return false;
340
+ default:
341
+ return true;
342
+ }
343
+ };
344
+ const classifyReference = (node, ancestors, scopes) => {
345
+ var _a;
346
+ let child = node;
347
+ for (let i = ancestors.length - 1; i >= 0; i--) {
348
+ const parent = ancestors[i];
349
+ if (!parent)
350
+ break;
351
+ switch (parent.type) {
352
+ case 'MemberExpression':
353
+ if (parent.object !== child)
354
+ return 'reads';
355
+ child = parent;
356
+ continue;
357
+ case 'ChainExpression':
358
+ case 'AwaitExpression':
359
+ case 'LogicalExpression':
360
+ child = parent;
361
+ continue;
362
+ case 'ConditionalExpression':
363
+ if (parent.test === child)
364
+ return 'reads';
365
+ child = parent;
366
+ continue;
367
+ case 'SequenceExpression':
368
+ if (parent.expressions[parent.expressions.length - 1] !== child)
369
+ return 'reads';
370
+ child = parent;
371
+ continue;
372
+ case 'CallExpression':
373
+ case 'NewExpression':
374
+ if (parent.callee === child) {
375
+ if (child.type !== 'MemberExpression')
376
+ return 'reads';
377
+ return !child.computed &&
378
+ child.property.type === 'Identifier' &&
379
+ NON_MUTATING_METHODS.has(child.property.name)
380
+ ? 'reads'
381
+ : 'mutates';
382
+ }
383
+ return parent.type === 'CallExpression' &&
384
+ parent.callee.type === 'Identifier' &&
385
+ CLASS_HELPERS.has(parent.callee.name)
386
+ ? 'reads'
387
+ : 'mutates';
388
+ case 'SpreadElement':
389
+ case 'ArrayExpression':
390
+ case 'ObjectExpression':
391
+ child = parent;
392
+ continue;
393
+ case 'Property':
394
+ if (parent.value !== child)
395
+ return 'reads';
396
+ child = parent;
397
+ continue;
398
+ case 'TemplateLiteral':
399
+ case 'BinaryExpression':
400
+ case 'TaggedTemplateExpression':
401
+ case 'IfStatement':
402
+ case 'WhileStatement':
403
+ case 'DoWhileStatement':
404
+ case 'SwitchStatement':
405
+ case 'SwitchCase':
406
+ return 'reads';
407
+ case 'UnaryExpression':
408
+ return parent.operator === 'delete' ? 'mutates' : 'reads';
409
+ case 'ExpressionStatement':
410
+ case 'JSXExpressionContainer':
411
+ case 'JSXSpreadAttribute':
412
+ return 'reads';
413
+ case 'VariableDeclarator': {
414
+ const declaration = ancestors[i - 1];
415
+ if (parent.init === child &&
416
+ parent.id.type === 'Identifier' &&
417
+ (declaration === null || declaration === void 0 ? void 0 : declaration.type) === 'VariableDeclaration' &&
418
+ declaration.kind === 'const') {
419
+ return (_a = resolveBinding(parent.id.name, scopes)) !== null && _a !== void 0 ? _a : 'mutates';
420
+ }
421
+ return 'mutates';
422
+ }
423
+ default:
424
+ return 'mutates';
425
+ }
426
+ }
427
+ return 'reads';
428
+ };
429
+ const transformMdxJsEsmNode = (estreeNode, moduleScopes, scopeByNode, context) => {
88
430
  const scopes = [...moduleScopes];
89
431
  walk(estreeNode, {
90
432
  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]);
433
+ const scope = scopeByNode.get(node);
434
+ if (scope)
101
435
  scopes.push(scope);
102
- return;
103
- }
104
- if (node.type === 'JSXAttribute' &&
105
- node.name.type === 'JSXIdentifier' &&
106
- (node.name.name === 'className' || node.name.name === 'class')) {
436
+ if (node.type === 'JSXAttribute' && isClassAttribute(node)) {
107
437
  // example: className="bg-green-500"
108
438
  if (node.value && node.value.type === 'Literal') {
109
- transformLiteral(node.value, tailwindSelectors);
439
+ transformLiteral(node.value, context);
110
440
  }
111
441
  if (node.value &&
112
442
  node.value.type === 'JSXExpressionContainer' &&
113
443
  node.value.expression.type !== 'JSXEmptyExpression') {
114
- node.value.expression = transformExpressionClassNames(node.value.expression, scopes, tailwindSelectors);
444
+ node.value.expression = transformExpressionClassNames(node.value.expression, scopes, context);
115
445
  }
116
446
  }
117
447
  },
118
448
  leave(node) {
119
- if (node.type === 'BlockStatement' || isFunctionNode(node)) {
449
+ if (scopeByNode.has(node))
120
450
  scopes.pop();
121
- }
122
451
  },
123
452
  });
124
453
  };
125
- const transformExpressionClassNames = (expr, scopes, tailwindSelectors, inlining = new Set()) => {
126
- const transform = (child) => transformExpressionClassNames(child, scopes, tailwindSelectors, inlining);
454
+ const transformExpressionClassNames = (expr, scopes, context, inlining = new Set(), structural = false) => {
455
+ const transform = (child) => transformExpressionClassNames(child, scopes, context, inlining);
456
+ const transformStructural = (child) => transformExpressionClassNames(child, scopes, context, inlining, true);
127
457
  const transformElement = (element) => {
128
458
  if (element.type !== 'SpreadElement')
129
459
  return transform(element);
130
- element.argument = transform(element.argument);
460
+ element.argument = transformStructural(element.argument);
131
461
  return element;
132
462
  };
133
463
  switch (expr.type) {
134
464
  case 'Literal':
135
- transformLiteral(expr, tailwindSelectors);
465
+ transformLiteral(expr, context);
136
466
  return expr;
137
467
  case 'TemplateLiteral':
138
468
  // example: className={`bg-green-500`}
139
469
  expr.quasis.forEach((quasi) => {
140
470
  if (quasi.value.cooked) {
141
- const transformedValue = transformClassNames(quasi.value.cooked, tailwindSelectors);
471
+ const transformedValue = transformClassNames(quasi.value.cooked, context.tailwindSelectors);
142
472
  if (quasi.value.cooked !== transformedValue) {
143
473
  quasi.value.cooked = transformedValue;
144
474
  quasi.value.raw = transformedValue;
475
+ context.changes.count++;
145
476
  }
146
477
  }
147
478
  });
@@ -150,13 +481,13 @@ const transformExpressionClassNames = (expr, scopes, tailwindSelectors, inlining
150
481
  return expr;
151
482
  case 'ConditionalExpression':
152
483
  // example: ${isActive ? "bg-red-500" : "bg-blue-500"}
153
- expr.consequent = transform(expr.consequent);
154
- expr.alternate = transform(expr.alternate);
484
+ expr.consequent = (structural ? transformStructural : transform)(expr.consequent);
485
+ expr.alternate = (structural ? transformStructural : transform)(expr.alternate);
155
486
  return expr;
156
487
  case 'LogicalExpression':
157
488
  // example: ${isActive && "bg-red-500"}
158
- expr.left = transform(expr.left);
159
- expr.right = transform(expr.right);
489
+ expr.left = (structural ? transformStructural : transform)(expr.left);
490
+ expr.right = (structural ? transformStructural : transform)(expr.right);
160
491
  return expr;
161
492
  case 'BinaryExpression':
162
493
  if (expr.operator === '+') {
@@ -174,60 +505,74 @@ const transformExpressionClassNames = (expr, scopes, tailwindSelectors, inlining
174
505
  return expr;
175
506
  // example: ["bg-red-500", "bg-blue-500"].join(" ")
176
507
  if (expr.callee.type === 'MemberExpression' && expr.callee.object.type !== 'Super') {
177
- expr.callee.object = transform(expr.callee.object);
508
+ expr.callee.object = transformStructural(expr.callee.object);
509
+ expr.arguments = expr.arguments.map(transformElement);
510
+ }
511
+ else {
512
+ expr.arguments = expr.arguments.map((argument) => argument.type === 'SpreadElement'
513
+ ? transformElement(argument)
514
+ : transformStructural(argument));
178
515
  }
179
- expr.arguments = expr.arguments.map(transformElement);
180
516
  return expr;
181
517
  case 'ObjectExpression':
182
518
  // example: cn({ "bg-blue-500": isActive })
183
- transformObjectKeys(expr, transform, tailwindSelectors);
519
+ transformObjectKeys(expr, transform, transformStructural, context);
184
520
  return expr;
185
521
  case 'MemberExpression':
186
522
  // example: const styles = { active: "bg-red-500" }; className={styles.active}
187
- return transformMemberExpression(expr, scopes, transform);
523
+ return transformMemberExpression(expr, scopes, transform, context);
188
524
  case 'Identifier': {
189
525
  // example: const classes = "bg-red-500"; className={classes}
190
526
  const binding = resolveBinding(expr.name, scopes);
191
- if (!(binding === null || binding === void 0 ? void 0 : binding.init) || inlining.has(binding))
527
+ if (!binding || inlining.has(binding))
192
528
  return expr;
193
- const inlined = cloneForUse(binding.init, binding.scopes, scopes, new Set([binding]));
194
- if (!inlined)
529
+ const inlined = cloneForUse(expr, scopes, scopes, createCloneState(context), structural);
530
+ if (!inlined || inlined.type === 'Identifier')
195
531
  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;
532
+ const nextInlining = new Set([...inlining, binding]);
533
+ return applyIfChanged(expr, inlined, (child) => transformExpressionClassNames(child, scopes, context, nextInlining), context);
199
534
  }
200
535
  default:
201
536
  return expr;
202
537
  }
203
538
  };
204
- const transformMemberExpression = (expr, scopes, transform) => {
539
+ const createCloneState = (context) => ({
540
+ inlining: new Set(),
541
+ local: { remaining: MAX_NODES_PER_INLINE },
542
+ page: context.pageBudget,
543
+ });
544
+ const applyIfChanged = (original, replacement, transform, context) => {
545
+ if (context.inlineDepth >= MAX_INLINE_DEPTH)
546
+ return original;
547
+ context.inlineDepth++;
548
+ const before = context.changes.count;
549
+ const transformed = transform(replacement);
550
+ context.inlineDepth--;
551
+ return context.changes.count === before ? original : transformed;
552
+ };
553
+ const transformMemberExpression = (expr, scopes, transform, context) => {
205
554
  if (getStaticKey(expr) !== undefined) {
206
555
  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;
556
+ const inlined = resolved && cloneForUse(resolved.expr, resolved.scopes, scopes, createCloneState(context));
557
+ return inlined ? applyIfChanged(expr, inlined, transform, context) : expr;
213
558
  }
214
- const object = resolveObject(expr.object, scopes);
559
+ const object = resolveObject(expr.object, scopes, context);
215
560
  if (!object)
216
561
  return expr;
217
- const before = serialize(object);
562
+ const before = context.changes.count;
218
563
  object.properties.forEach((property) => {
219
564
  const value = property.type === 'Property' ? asExpression(property.value) : undefined;
220
565
  if (property.type === 'Property' && value)
221
566
  property.value = transform(value);
222
567
  });
223
- if (serialize(object) !== before)
568
+ if (context.changes.count !== before)
224
569
  expr.object = object;
225
570
  return expr;
226
571
  };
227
- const transformObjectKeys = (expr, transform, tailwindSelectors) => {
572
+ const transformObjectKeys = (expr, transform, transformStructural, context) => {
228
573
  expr.properties.forEach((property) => {
229
574
  if (property.type === 'SpreadElement') {
230
- property.argument = transform(property.argument);
575
+ property.argument = transformStructural(property.argument);
231
576
  return;
232
577
  }
233
578
  if (property.computed) {
@@ -238,51 +583,149 @@ const transformObjectKeys = (expr, transform, tailwindSelectors) => {
238
583
  const keyName = getPropertyKeyName(property);
239
584
  if (keyName === undefined)
240
585
  return;
241
- const transformedValue = transformClassNames(keyName, tailwindSelectors);
586
+ const transformedValue = transformClassNames(keyName, context.tailwindSelectors);
242
587
  if (keyName !== transformedValue) {
243
588
  property.key = toLiteral(transformedValue);
244
589
  property.shorthand = false;
590
+ context.changes.count++;
245
591
  }
246
592
  });
247
593
  };
248
- const resolveObject = (node, scopes) => {
594
+ const resolveObject = (node, scopes, context) => {
249
595
  if (node.type === 'ObjectExpression')
250
596
  return node;
251
597
  const resolved = resolveStaticValue(node, scopes);
252
598
  if ((resolved === null || resolved === void 0 ? void 0 : resolved.expr.type) !== 'ObjectExpression')
253
599
  return undefined;
254
- const cloned = cloneForUse(resolved.expr, resolved.scopes, scopes, new Set());
600
+ const cloned = cloneForUse(resolved.expr, resolved.scopes, scopes, createCloneState(context));
255
601
  return (cloned === null || cloned === void 0 ? void 0 : cloned.type) === 'ObjectExpression' ? cloned : undefined;
256
602
  };
257
- const resolveStaticValue = (node, scopes, resolving = new Set()) => {
258
- if (node.type === 'Super')
603
+ const resolveStaticValue = (node, scopes, resolving = new Set(), depth = 0) => {
604
+ if (node.type === 'Super' || depth >= MAX_INLINE_DEPTH)
259
605
  return undefined;
260
606
  if (node.type === 'Identifier') {
261
607
  const binding = resolveBinding(node.name, scopes);
262
608
  if (!(binding === null || binding === void 0 ? void 0 : binding.init))
263
609
  return { expr: node, scopes };
264
- if (resolving.has(binding))
610
+ if (resolving.has(binding) || binding.mutated)
265
611
  return undefined;
266
- return resolveStaticValue(binding.init, binding.scopes, new Set([...resolving, binding]));
612
+ return resolveStaticValue(binding.init, binding.scopes, new Set([...resolving, binding]), depth + 1);
267
613
  }
268
614
  if (node.type === 'MemberExpression') {
269
615
  const key = getStaticKey(node);
270
616
  if (key === undefined)
271
617
  return { expr: node, scopes };
272
- const object = resolveStaticValue(node.object, scopes, resolving);
618
+ const object = resolveStaticValue(node.object, scopes, resolving, depth + 1);
273
619
  if ((object === null || object === void 0 ? void 0 : object.expr.type) !== 'ObjectExpression')
274
620
  return undefined;
275
621
  const value = findPropertyValue(object.expr, key);
276
- return value && resolveStaticValue(value, object.scopes, resolving);
622
+ return value && resolveStaticValue(value, object.scopes, resolving, depth + 1);
277
623
  }
278
624
  return { expr: node, scopes };
279
625
  };
280
- const cloneForUse = (expr, declarationScopes, useScopes, inlining) => {
281
- const clone = (child) => cloneForUse(child, declarationScopes, useScopes, inlining);
626
+ const createsObjectCache = new WeakMap();
627
+ const isStringCache = new WeakMap();
628
+ const createsObject = (expr, scopes, visiting = new Set(), depth = 0) => {
629
+ const cached = createsObjectCache.get(expr);
630
+ if (cached !== undefined)
631
+ return cached;
632
+ if (depth >= MAX_INLINE_DEPTH)
633
+ return true;
634
+ const result = computeCreatesObject(expr, scopes, visiting, depth);
635
+ createsObjectCache.set(expr, result);
636
+ return result;
637
+ };
638
+ const computeCreatesObject = (expr, scopes, visiting, depth) => {
639
+ const check = (child) => createsObject(child, scopes, visiting, depth);
640
+ switch (expr.type) {
641
+ case 'Literal':
642
+ return 'regex' in expr;
643
+ case 'TemplateLiteral':
644
+ case 'BinaryExpression':
645
+ case 'UnaryExpression':
646
+ return false;
647
+ case 'ConditionalExpression':
648
+ return check(expr.consequent) || check(expr.alternate);
649
+ case 'LogicalExpression':
650
+ return check(expr.left) || check(expr.right);
651
+ case 'CallExpression':
652
+ if (!isClassCall(expr) || expr.callee.type === 'Super')
653
+ return true;
654
+ if (expr.callee.type === 'Identifier')
655
+ return false;
656
+ if (expr.callee.type !== 'MemberExpression' || expr.callee.object.type === 'Super')
657
+ return true;
658
+ return (expr.callee.property.type === 'Identifier' &&
659
+ expr.callee.property.name === 'concat' &&
660
+ !isString(expr.callee.object, scopes, visiting, depth));
661
+ case 'Identifier': {
662
+ const binding = resolveBinding(expr.name, scopes);
663
+ if (!(binding === null || binding === void 0 ? void 0 : binding.init) || visiting.has(binding))
664
+ return false;
665
+ return createsObject(binding.init, binding.scopes, new Set([...visiting, binding]), depth + 1);
666
+ }
667
+ case 'MemberExpression': {
668
+ const resolved = resolveStaticValue(expr, scopes);
669
+ if (resolved && resolved.expr !== expr) {
670
+ return createsObject(resolved.expr, resolved.scopes, visiting, depth + 1);
671
+ }
672
+ return (expr.object.type !== 'Super' && createsObject(expr.object, scopes, visiting, depth + 1));
673
+ }
674
+ default:
675
+ return true;
676
+ }
677
+ };
678
+ const isString = (expr, scopes, visiting, depth) => {
679
+ const cached = isStringCache.get(expr);
680
+ if (cached !== undefined)
681
+ return cached;
682
+ if (depth >= MAX_INLINE_DEPTH)
683
+ return false;
684
+ const result = computeIsString(expr, scopes, visiting, depth);
685
+ isStringCache.set(expr, result);
686
+ return result;
687
+ };
688
+ const computeIsString = (expr, scopes, visiting, depth) => {
689
+ switch (expr.type) {
690
+ case 'Literal':
691
+ return typeof expr.value === 'string';
692
+ case 'TemplateLiteral':
693
+ return true;
694
+ case 'BinaryExpression':
695
+ return (expr.operator === '+' &&
696
+ (isString(expr.left, scopes, visiting, depth) ||
697
+ isString(expr.right, scopes, visiting, depth)));
698
+ case 'CallExpression':
699
+ return isClassCall(expr) && !createsObject(expr, scopes, visiting, depth);
700
+ case 'Identifier': {
701
+ const binding = resolveBinding(expr.name, scopes);
702
+ if (!(binding === null || binding === void 0 ? void 0 : binding.init) || visiting.has(binding))
703
+ return false;
704
+ return isString(binding.init, binding.scopes, new Set([...visiting, binding]), depth + 1);
705
+ }
706
+ default:
707
+ return false;
708
+ }
709
+ };
710
+ const getRootIdentifier = (expr) => {
711
+ if (expr.type === 'Identifier')
712
+ return expr;
713
+ if (expr.type === 'MemberExpression')
714
+ return getRootIdentifier(expr.object);
715
+ return undefined;
716
+ };
717
+ const cloneForUse = (expr, declarationScopes, useScopes, state, structural = false) => {
718
+ var _a;
719
+ state.local.remaining--;
720
+ state.page.remaining--;
721
+ if (state.local.remaining < 0 || state.page.remaining < 0)
722
+ return undefined;
723
+ const clone = (child) => cloneForUse(child, declarationScopes, useScopes, state);
724
+ const cloneStructural = (child) => cloneForUse(child, declarationScopes, useScopes, state, true);
282
725
  const cloneElement = (element) => {
283
726
  if (element.type !== 'SpreadElement')
284
727
  return clone(element);
285
- const argument = clone(element.argument);
728
+ const argument = cloneStructural(element.argument);
286
729
  return argument && Object.assign(Object.assign({}, element), { argument });
287
730
  };
288
731
  const cloneAll = (items, cloneItem) => {
@@ -312,24 +755,26 @@ const cloneForUse = (expr, declarationScopes, useScopes, inlining) => {
312
755
  return left && right && Object.assign(Object.assign({}, expr), { left, right });
313
756
  }
314
757
  case 'LogicalExpression': {
315
- const left = clone(expr.left);
316
- const right = clone(expr.right);
758
+ const left = (structural ? cloneStructural : clone)(expr.left);
759
+ const right = (structural ? cloneStructural : clone)(expr.right);
317
760
  return left && right && Object.assign(Object.assign({}, expr), { left, right });
318
761
  }
319
762
  case 'ConditionalExpression': {
320
763
  const test = clone(expr.test);
321
- const consequent = clone(expr.consequent);
322
- const alternate = clone(expr.alternate);
764
+ const consequent = (structural ? cloneStructural : clone)(expr.consequent);
765
+ const alternate = (structural ? cloneStructural : clone)(expr.alternate);
323
766
  return test && consequent && alternate && Object.assign(Object.assign({}, expr), { test, consequent, alternate });
324
767
  }
325
768
  case 'UnaryExpression': {
769
+ if (expr.operator === 'delete')
770
+ return undefined;
326
771
  const argument = clone(expr.argument);
327
772
  return argument && Object.assign(Object.assign({}, expr), { argument });
328
773
  }
329
774
  case 'ObjectExpression': {
330
775
  const properties = cloneAll(expr.properties, (property) => {
331
776
  if (property.type === 'SpreadElement') {
332
- const argument = clone(property.argument);
777
+ const argument = cloneStructural(property.argument);
333
778
  return argument && Object.assign(Object.assign({}, property), { argument });
334
779
  }
335
780
  if (property.kind !== 'init' || property.method)
@@ -352,7 +797,10 @@ const cloneForUse = (expr, declarationScopes, useScopes, inlining) => {
352
797
  if (expr.object.type === 'Super' || expr.property.type === 'PrivateIdentifier') {
353
798
  return undefined;
354
799
  }
355
- const object = clone(expr.object);
800
+ const root = getRootIdentifier(expr.object);
801
+ if (root && ((_a = resolveBinding(root.name, declarationScopes)) === null || _a === void 0 ? void 0 : _a.mutated))
802
+ return undefined;
803
+ const object = cloneStructural(expr.object);
356
804
  const property = expr.computed ? clone(expr.property) : structuredClone(expr.property);
357
805
  return object && property && Object.assign(Object.assign({}, expr), { object, property });
358
806
  }
@@ -360,17 +808,28 @@ const cloneForUse = (expr, declarationScopes, useScopes, inlining) => {
360
808
  if (!isClassCall(expr) || expr.callee.type === 'Super')
361
809
  return undefined;
362
810
  const callee = clone(expr.callee);
363
- const args = cloneAll(expr.arguments, cloneElement);
811
+ const args = cloneAll(expr.arguments, (argument) => expr.callee.type === 'Identifier' && argument.type !== 'SpreadElement'
812
+ ? cloneStructural(argument)
813
+ : cloneElement(argument));
364
814
  return callee && args && Object.assign(Object.assign({}, expr), { callee, arguments: args });
365
815
  }
366
816
  case 'Identifier': {
367
817
  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]));
818
+ if ((binding === null || binding === void 0 ? void 0 : binding.init) &&
819
+ !state.inlining.has(binding) &&
820
+ state.inlining.size < MAX_INLINE_DEPTH &&
821
+ (!createsObject(binding.init, binding.scopes) || (structural && !binding.mutated))) {
822
+ state.inlining.add(binding);
823
+ const inlined = cloneForUse(binding.init, binding.scopes, useScopes, state, structural);
824
+ state.inlining.delete(binding);
370
825
  if (inlined)
371
826
  return inlined;
372
827
  }
373
- return binding === resolveBinding(expr.name, useScopes) ? structuredClone(expr) : undefined;
828
+ const useBinding = resolveBinding(expr.name, useScopes);
829
+ const isStable = binding
830
+ ? !binding.reassigned && !binding.mutated && binding === useBinding
831
+ : !useBinding && IMMUTABLE_GLOBALS.has(expr.name);
832
+ return isStable ? structuredClone(expr) : undefined;
374
833
  }
375
834
  default:
376
835
  return undefined;
@@ -406,8 +865,17 @@ const findPropertyValue = (object, key) => {
406
865
  const property = object.properties[i];
407
866
  if (!property || property.type === 'SpreadElement')
408
867
  return undefined;
409
- if (getPropertyKeyName(property) === key)
410
- return asExpression(property.value);
868
+ const name = getPropertyKeyName(property);
869
+ if (name === undefined) {
870
+ if (property.computed)
871
+ return undefined;
872
+ continue;
873
+ }
874
+ if (name !== key)
875
+ continue;
876
+ if (property.kind !== 'init' || property.method)
877
+ return undefined;
878
+ return asExpression(property.value);
411
879
  }
412
880
  return undefined;
413
881
  };
@@ -417,15 +885,16 @@ const asExpression = (node) => node.type === 'ObjectPattern' ||
417
885
  node.type === 'AssignmentPattern'
418
886
  ? undefined
419
887
  : node;
420
- const transformLiteral = (expr, tailwindSelectors) => {
888
+ const transformLiteral = (expr, context) => {
421
889
  if (typeof expr.value !== 'string')
422
890
  return;
423
- const transformedValue = transformClassNames(expr.value, tailwindSelectors);
891
+ const transformedValue = transformClassNames(expr.value, context.tailwindSelectors);
424
892
  if (expr.value !== transformedValue) {
425
893
  expr.value = transformedValue;
426
894
  if (typeof expr.raw === 'string') {
427
895
  expr.raw = JSON.stringify(transformedValue);
428
896
  }
897
+ context.changes.count++;
429
898
  }
430
899
  };
431
900
  const toLiteral = (value) => ({
@@ -433,7 +902,6 @@ const toLiteral = (value) => ({
433
902
  value,
434
903
  raw: JSON.stringify(value),
435
904
  });
436
- const serialize = (node) => JSON.stringify(node, (_key, value) => typeof value === 'bigint' ? value.toString() : value);
437
905
  const transformClassNames = (value, tailwindSelectors) => {
438
906
  var _a, _b, _c, _d;
439
907
  if (!tailwindSelectors || !tailwindSelectors.length)