@mintlify/common 1.0.1257 → 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)
@@ -1,7 +1,9 @@
1
1
  import { visit } from 'unist-util-visit';
2
2
  import { normalizeGroups } from '../../../navigation/groupAccess.js';
3
3
  import { safeCleanHeadingId, slugify } from '../../../slugify.js';
4
+ import { MINT_ISLAND_COMPONENT } from '../../islands/packageImports.js';
4
5
  import { createMdxJsxAttribute, getTableOfContentsTitle, getTitleMarkdownText, } from '../../lib/remark-utils.js';
6
+ import { createSlugDeduplicator } from '../../lib/slug-deduplicator.js';
5
7
  import { isMdxJsxFragment } from '../../utils.js';
6
8
  import { AVOIDED_PAGE_MODES, HEADING_LEVELS } from './remarkComponentIds.js';
7
9
  import { isHiddenFromHumans, isVisibilityElement, resolveVisibilityFor, toPageGroups, toVisibilityAuthRule, } from './remarkVisibilityForMarkdown.js';
@@ -37,23 +39,9 @@ const hasAuthRules = (childRules, parentRules) => {
37
39
  export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
38
40
  // Unified slug deduplication: both custom IDs and auto-generated slugs
39
41
  // share the same seen-slug state so they cannot collide.
40
- const seenSlugs = new Map();
41
- const deduplicateSlug = (slug) => {
42
- var _a;
43
- const count = (_a = seenSlugs.get(slug)) !== null && _a !== void 0 ? _a : 0;
44
- seenSlugs.set(slug, count + 1);
45
- if (count === 0)
46
- return slug;
47
- let suffix = count + 1;
48
- let suffixed = `${slug}-${suffix}`;
49
- while (seenSlugs.has(suffixed)) {
50
- suffix += 1;
51
- suffixed = `${slug}-${suffix}`;
52
- }
53
- seenSlugs.set(suffixed, 1);
54
- return suffixed;
55
- };
42
+ const slugs = createSlugDeduplicator();
56
43
  return (tree) => {
44
+ var _a;
57
45
  const contents = [];
58
46
  let hasTopLayer = false;
59
47
  // the key is the node in unist
@@ -66,7 +54,13 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
66
54
  // doesn't set its own titleSize, so the TOC must honor the same fallback.
67
55
  const inheritedStepTitleSizeMap = new Map();
68
56
  const excludedNodes = new Set();
57
+ const isAvoidedPageMode = AVOIDED_PAGE_MODES.includes((_a = pageMetadata === null || pageMetadata === void 0 ? void 0 : pageMetadata.mode) !== null && _a !== void 0 ? _a : '');
69
58
  visit(tree, (node) => {
59
+ var _a, _b;
60
+ if (node.type === 'mdxJsxFlowElement' && node.name === MINT_ISLAND_COMPONENT) {
61
+ for (const heading of (_b = (_a = node.data) === null || _a === void 0 ? void 0 : _a.islandHeadings) !== null && _b !== void 0 ? _b : [])
62
+ slugs.reserve(heading.slug);
63
+ }
70
64
  if (node.type === 'mdxJsxFlowElement' &&
71
65
  node.name &&
72
66
  COMPONENTS_TO_EXCLUDE_HEADINGS.includes(node.name)) {
@@ -177,7 +171,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
177
171
  arrToPushInto.push(entry);
178
172
  };
179
173
  visit(tree, (node) => {
180
- var _a, _b, _c, _d, _e, _f, _g, _h;
174
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
181
175
  if (excludedNodes.has(node))
182
176
  return;
183
177
  const currentTabId = tabContentMap.get(node);
@@ -191,9 +185,8 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
191
185
  // headings compiled inside an <MDX> fragment (see remarkMdxExpandExpressions); merged in
192
186
  // document order, slugs registered so later page headings do not reuse them
193
187
  const register = (entries) => {
194
- var _a;
195
188
  for (const entry of entries) {
196
- seenSlugs.set(entry.slug, ((_a = seenSlugs.get(entry.slug)) !== null && _a !== void 0 ? _a : 0) + 1);
189
+ slugs.reserve(entry.slug);
197
190
  register(entry.children);
198
191
  }
199
192
  };
@@ -205,14 +198,31 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
205
198
  }
206
199
  return;
207
200
  }
201
+ if (node.type === 'mdxJsxFlowElement' && node.name === MINT_ISLAND_COMPONENT) {
202
+ if (isAvoidedPageMode)
203
+ return;
204
+ for (const { title, slug, depth } of (_d = (_c = node.data) === null || _c === void 0 ? void 0 : _c.islandHeadings) !== null && _d !== void 0 ? _d : []) {
205
+ pushEntry({
206
+ title,
207
+ slug,
208
+ depth,
209
+ children: [],
210
+ tabId: currentTabId,
211
+ viewId: currentViewId,
212
+ variationIds: currentVariationIds,
213
+ authRules: currentAuthRules,
214
+ }, depth);
215
+ }
216
+ return;
217
+ }
208
218
  const isValidHeading = node.type === 'heading' && HEADING_LEVELS.includes(node.depth);
209
- const isValidMdxHeading = node.type === 'mdxJsxFlowElement' && HEADING_NAMES.includes((_c = node.name) !== null && _c !== void 0 ? _c : '');
219
+ const isValidMdxHeading = node.type === 'mdxJsxFlowElement' && HEADING_NAMES.includes((_e = node.name) !== null && _e !== void 0 ? _e : '');
210
220
  const isTransformedHeading = node.type === 'mdxJsxFlowElement' && node.name === 'Heading';
211
221
  const isValidUpdate = node.type === 'mdxJsxFlowElement' &&
212
222
  node.name === 'Update' &&
213
223
  node.attributes.some((attr) => 'name' in attr && attr.name === 'label');
214
224
  const stepTitleSize = node.type === 'mdxJsxFlowElement' && node.name === 'Step'
215
- ? ((_d = getStringAttribute(node.attributes, 'titleSize')) !== null && _d !== void 0 ? _d : inheritedStepTitleSizeMap.get(node))
225
+ ? ((_f = getStringAttribute(node.attributes, 'titleSize')) !== null && _f !== void 0 ? _f : inheritedStepTitleSizeMap.get(node))
216
226
  : undefined;
217
227
  const hasNoAnchor = node.type === 'mdxJsxFlowElement' &&
218
228
  node.attributes.some((attr) => 'name' in attr &&
@@ -221,7 +231,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
221
231
  attr.value === 'true' ||
222
232
  (typeof attr.value === 'object' && attr.value.value === 'true')));
223
233
  const stepTitle = node.type === 'mdxJsxFlowElement' && node.name === 'Step'
224
- ? getTitleMarkdownText(node, (_e = getStringAttribute(node.attributes, 'title')) !== null && _e !== void 0 ? _e : '')
234
+ ? getTitleMarkdownText(node, (_g = getStringAttribute(node.attributes, 'title')) !== null && _g !== void 0 ? _g : '')
225
235
  : undefined;
226
236
  const isValidStep = node.type === 'mdxJsxFlowElement' &&
227
237
  node.name === 'Step' &&
@@ -230,7 +240,6 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
230
240
  (stepTitle === null || stepTitle === void 0 ? void 0 : stepTitle.trim()) !== '';
231
241
  const hasIdAttribute = node.type === 'mdxJsxFlowElement' &&
232
242
  node.attributes.some((attr) => 'name' in attr && attr.name === 'id');
233
- const isAvoidedPageMode = AVOIDED_PAGE_MODES.includes((_f = pageMetadata === null || pageMetadata === void 0 ? void 0 : pageMetadata.mode) !== null && _f !== void 0 ? _f : '');
234
243
  if (!isValidHeading &&
235
244
  !isValidMdxHeading &&
236
245
  !isTransformedHeading &&
@@ -248,7 +257,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
248
257
  }
249
258
  else if ('name' in node && node.name === 'Step') {
250
259
  const titleSizeToLevel = { h2: 2, h3: 3, h4: 4 };
251
- level = (_g = titleSizeToLevel[stepTitleSize !== null && stepTitleSize !== void 0 ? stepTitleSize : '']) !== null && _g !== void 0 ? _g : 3;
260
+ level = (_h = titleSizeToLevel[stepTitleSize !== null && stepTitleSize !== void 0 ? stepTitleSize : '']) !== null && _h !== void 0 ? _h : 3;
252
261
  // @ts-expect-error we're assigning to depth despite the node not containing depth in the type
253
262
  node.depth = level;
254
263
  }
@@ -261,7 +270,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
261
270
  level = levelAttr.value;
262
271
  }
263
272
  }
264
- else if ('name' in node && ((_h = node.name) === null || _h === void 0 ? void 0 : _h[1])) {
273
+ else if ('name' in node && ((_j = node.name) === null || _j === void 0 ? void 0 : _j[1])) {
265
274
  const num = Number(node.name[1]);
266
275
  level = !isNaN(num) ? num : undefined;
267
276
  if (level !== undefined) {
@@ -277,10 +286,10 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
277
286
  ? getStringAttribute(node.attributes, 'id')
278
287
  : undefined;
279
288
  if (explicitId) {
280
- slug = deduplicateSlug(safeCleanHeadingId(explicitId) || slugify(title));
289
+ slug = slugs.claim(safeCleanHeadingId(explicitId) || slugify(title));
281
290
  }
282
291
  else {
283
- slug = deduplicateSlug(slugify(title));
292
+ slug = slugs.claim(slugify(title));
284
293
  }
285
294
  let mdxJsxAttributes;
286
295
  if ('name' in node && node.name === 'Update') {