@mintlify/common 1.0.939 → 1.0.941

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.
@@ -22,110 +22,208 @@ function getVisibilityFor(node) {
22
22
  }
23
23
  return undefined;
24
24
  }
25
- function getStringAttribute(node, name) {
26
- for (const attr of node.attributes) {
27
- if (attr.type === 'mdxJsxAttribute' && attr.name === name && typeof attr.value === 'string') {
28
- return attr.value;
29
- }
30
- }
31
- return undefined;
32
- }
33
25
  // `export * from` is intentionally ignored: it exposes no statically-knowable
34
26
  // names and creates no page-local JSX bindings in MDX, so there is nothing to
35
- // collect for ghost-tag stripping.
36
- function collectEsmIdentifiers(children) {
27
+ // collect.
28
+ function collectEsmIdentifiers(node) {
37
29
  var _a, _b, _c;
38
30
  const names = new Set();
39
- for (const child of children) {
40
- if (child.type !== 'mdxjsEsm')
41
- continue;
42
- for (const statement of (_c = (_b = (_a = child.data) === null || _a === void 0 ? void 0 : _a.estree) === null || _b === void 0 ? void 0 : _b.body) !== null && _c !== void 0 ? _c : []) {
43
- if (statement.type === 'ImportDeclaration') {
44
- for (const specifier of statement.specifiers) {
45
- names.add(specifier.local.name);
46
- }
31
+ if (node.type !== 'mdxjsEsm')
32
+ return names;
33
+ for (const statement of (_c = (_b = (_a = node.data) === null || _a === void 0 ? void 0 : _a.estree) === null || _b === void 0 ? void 0 : _b.body) !== null && _c !== void 0 ? _c : []) {
34
+ if (statement.type === 'ImportDeclaration') {
35
+ for (const specifier of statement.specifiers) {
36
+ names.add(specifier.local.name);
47
37
  }
48
- if (statement.type === 'ExportNamedDeclaration') {
49
- if (statement.declaration) {
50
- if (statement.declaration.type === 'VariableDeclaration') {
51
- for (const declarator of statement.declaration.declarations) {
52
- if (declarator.id.type === 'Identifier') {
53
- names.add(declarator.id.name);
54
- }
38
+ }
39
+ if (statement.type === 'ExportNamedDeclaration') {
40
+ if (statement.declaration) {
41
+ if (statement.declaration.type === 'VariableDeclaration') {
42
+ for (const declarator of statement.declaration.declarations) {
43
+ if (declarator.id.type === 'Identifier') {
44
+ names.add(declarator.id.name);
55
45
  }
56
46
  }
57
- else if (statement.declaration.id) {
58
- names.add(statement.declaration.id.name);
59
- }
60
47
  }
61
- // Re-exports: `export { Panel } from '...'` keep names in specifiers
62
- for (const specifier of statement.specifiers) {
63
- if (specifier.local.type === 'Identifier') {
64
- names.add(specifier.local.name);
65
- }
66
- if (specifier.exported.type === 'Identifier') {
67
- names.add(specifier.exported.name);
68
- }
48
+ else if (statement.declaration.id) {
49
+ names.add(statement.declaration.id.name);
69
50
  }
70
51
  }
71
- if (statement.type === 'ExportDefaultDeclaration') {
72
- const declaration = statement.declaration;
73
- if ((declaration.type === 'FunctionDeclaration' || declaration.type === 'ClassDeclaration') &&
74
- declaration.id) {
75
- names.add(declaration.id.name);
52
+ // Re-exports: `export { Panel } from '...'` keep names in specifiers
53
+ for (const specifier of statement.specifiers) {
54
+ if (specifier.local.type === 'Identifier') {
55
+ names.add(specifier.local.name);
56
+ }
57
+ if (specifier.exported.type === 'Identifier') {
58
+ names.add(specifier.exported.name);
76
59
  }
77
60
  }
78
61
  }
62
+ if (statement.type === 'ExportDefaultDeclaration') {
63
+ const declaration = statement.declaration;
64
+ if ((declaration.type === 'FunctionDeclaration' || declaration.type === 'ClassDeclaration') &&
65
+ declaration.id) {
66
+ names.add(declaration.id.name);
67
+ }
68
+ }
79
69
  }
80
70
  return names;
81
71
  }
82
- function transformChildren(children, strippedNames) {
83
- return children.flatMap((child) => transformNode(child, strippedNames));
72
+ function isRecord(value) {
73
+ return typeof value === 'object' && value !== null;
74
+ }
75
+ function getJsxReferenceBaseName(name) {
76
+ let current = name;
77
+ while (isRecord(current) && current.type === 'JSXMemberExpression') {
78
+ current = current.object;
79
+ }
80
+ if (isRecord(current) && current.type === 'JSXIdentifier' && typeof current.name === 'string') {
81
+ return current.name;
82
+ }
83
+ return undefined;
84
84
  }
85
- function transformNode(node, strippedNames) {
85
+ // Walks an estree for JSX component references, e.g. `<Logo />` within
86
+ // `export const Header = () => <Logo />` or `{<Demo />}` expressions.
87
+ function collectEstreeJsxNames(estree, names) {
88
+ const queue = [estree];
89
+ const seen = new Set();
90
+ while (queue.length > 0) {
91
+ const current = queue.pop();
92
+ if (Array.isArray(current)) {
93
+ queue.push(...current);
94
+ continue;
95
+ }
96
+ if (!isRecord(current) || seen.has(current))
97
+ continue;
98
+ seen.add(current);
99
+ if (current.type === 'JSXOpeningElement') {
100
+ const baseName = getJsxReferenceBaseName(current.name);
101
+ // Lowercase JSX names are intrinsic elements, never component bindings.
102
+ if (baseName && /^[A-Z]/.test(baseName))
103
+ names.add(baseName);
104
+ }
105
+ queue.push(...Object.values(current));
106
+ }
107
+ }
108
+ // JSX rendered inside an ESM node's own declarations, so stripping `Header`
109
+ // can also pull in helpers that only exist to serve it.
110
+ function collectJsxReferences(node) {
86
111
  var _a;
87
- // The output is terminal agent-facing markdown, never re-parsed as MDX, so
88
- // ESM is dropped wholesale even when kept content references its components.
112
+ const names = new Set();
89
113
  if (node.type === 'mdxjsEsm') {
90
- return [];
114
+ collectEstreeJsxNames((_a = node.data) === null || _a === void 0 ? void 0 : _a.estree, names);
91
115
  }
92
- if (isMdxJsxElement(node)) {
93
- if (node.name === 'Visibility') {
94
- const audience = getVisibilityFor(node);
95
- if (audience === 'humans') {
96
- return [];
116
+ return names;
117
+ }
118
+ // Classifies every JSX component usage on the page: names used only inside
119
+ // `<Visibility for="humans">` land in `hiddenNames`, everything else in
120
+ // `visibleNames`. Usage inside an agents block counts as visible since that
121
+ // content survives into the markdown output.
122
+ function collectJsxUsage(nodes, insideHumans, hiddenNames, visibleNames) {
123
+ var _a, _b;
124
+ for (const node of nodes) {
125
+ let childInsideHumans = insideHumans;
126
+ if (isMdxJsxElement(node)) {
127
+ if (node.name === 'Visibility') {
128
+ if (getVisibilityFor(node) === 'humans')
129
+ childInsideHumans = true;
97
130
  }
98
- if (audience === 'agents') {
99
- return transformChildren(node.children, strippedNames);
131
+ else {
132
+ const baseName = (_a = node.name) === null || _a === void 0 ? void 0 : _a.split('.')[0];
133
+ // Lowercase JSX names are intrinsic elements, never component bindings.
134
+ if (baseName && /^[A-Z]/.test(baseName)) {
135
+ (insideHumans ? hiddenNames : visibleNames).add(baseName);
136
+ }
100
137
  }
101
138
  }
102
- // Usages of components whose page-local definition was stripped above
103
- // would serialize as unresolvable ghost tags; unwrap them so only their
104
- // real child content (if any) survives. A title attribute often labels
105
- // that content, so carry it over as emphasized text.
106
- const baseName = (_a = node.name) === null || _a === void 0 ? void 0 : _a.split('.')[0];
107
- if (baseName && strippedNames.has(baseName)) {
108
- const unwrapped = transformChildren(node.children, strippedNames);
109
- const title = getStringAttribute(node, 'title');
110
- if (node.type === 'mdxJsxFlowElement' && title) {
111
- return [
112
- {
113
- type: 'paragraph',
114
- children: [{ type: 'strong', children: [{ type: 'text', value: title }] }],
115
- },
116
- ...unwrapped,
117
- ];
118
- }
119
- return unwrapped;
139
+ // Expression-embedded usages like `{<Demo />}` live in estree, not mdast.
140
+ if (node.type === 'mdxFlowExpression' || node.type === 'mdxTextExpression') {
141
+ collectEstreeJsxNames((_b = node.data) === null || _b === void 0 ? void 0 : _b.estree, insideHumans ? hiddenNames : visibleNames);
142
+ }
143
+ if ('children' in node && Array.isArray(node.children)) {
144
+ collectJsxUsage(node.children, childInsideHumans, hiddenNames, visibleNames);
145
+ }
146
+ }
147
+ }
148
+ function transformChildren(children, esmToStrip) {
149
+ return children.flatMap((child) => transformNode(child, esmToStrip));
150
+ }
151
+ function transformNode(node, esmToStrip) {
152
+ // Snippet definitions are only stripped when every usage of the components
153
+ // they declare sits inside a `<Visibility for="humans">` block; JSX that the
154
+ // author left visible keeps its definition in the markdown output.
155
+ if (node.type === 'mdxjsEsm') {
156
+ return esmToStrip.has(node) ? [] : [node];
157
+ }
158
+ if (isMdxJsxElement(node) && node.name === 'Visibility') {
159
+ const audience = getVisibilityFor(node);
160
+ if (audience === 'humans') {
161
+ return [];
162
+ }
163
+ if (audience === 'agents') {
164
+ return transformChildren(node.children, esmToStrip);
120
165
  }
121
166
  }
122
167
  if ('children' in node && Array.isArray(node.children)) {
123
- const next = transformChildren(node.children, strippedNames);
168
+ const next = transformChildren(node.children, esmToStrip);
124
169
  node.children = next;
125
170
  }
126
171
  return [node];
127
172
  }
128
173
  export const remarkVisibilityForMarkdown = () => (tree) => {
129
- const strippedNames = collectEsmIdentifiers(tree.children);
130
- tree.children = transformChildren(tree.children, strippedNames);
174
+ var _a, _b, _c, _d;
175
+ const hiddenNames = new Set();
176
+ const visibleNames = new Set();
177
+ collectJsxUsage(tree.children, false, hiddenNames, visibleNames);
178
+ const esmNodes = tree.children.filter((child) => child.type === 'mdxjsEsm');
179
+ const declaredNames = new Map(esmNodes.map((node) => [node, [...collectEsmIdentifiers(node)]]));
180
+ const referencedNames = new Map(esmNodes.map((node) => [node, [...collectJsxReferences(node)]]));
181
+ const esmToStrip = new Set();
182
+ // Keep-alive fixed point: a node with any visibly-used name keeps every
183
+ // name it declares or renders visible, so a visible `<PanelAlias />` keeps
184
+ // the `export const Panel = ...` node it aliases, and a kept `Footer` keeps
185
+ // the `Logo` helper it renders, even when both live in separate ESM nodes.
186
+ let visibleChanged = true;
187
+ while (visibleChanged) {
188
+ visibleChanged = false;
189
+ for (const node of esmNodes) {
190
+ const declared = (_a = declaredNames.get(node)) !== null && _a !== void 0 ? _a : [];
191
+ if (!declared.some((name) => visibleNames.has(name)))
192
+ continue;
193
+ for (const name of [...declared, ...((_b = referencedNames.get(node)) !== null && _b !== void 0 ? _b : [])]) {
194
+ if (!visibleNames.has(name)) {
195
+ visibleNames.add(name);
196
+ visibleChanged = true;
197
+ }
198
+ }
199
+ }
200
+ }
201
+ // Fixed point: stripping a node marks everything it declares or renders as
202
+ // hidden, so `export { Panel as PanelAlias }` pulls in the `export const
203
+ // Panel = ...` it aliases, and a stripped `Header` pulls in the `Logo`
204
+ // helper rendered only inside its body, instead of leaking their source.
205
+ let changed = true;
206
+ while (changed) {
207
+ changed = false;
208
+ for (const node of esmNodes) {
209
+ if (esmToStrip.has(node))
210
+ continue;
211
+ const names = (_c = declaredNames.get(node)) !== null && _c !== void 0 ? _c : [];
212
+ // Declared-but-never-rendered names don't block stripping: when a node
213
+ // mixes a hidden component with unused names, hiding wins over leaking.
214
+ const hiddenOnly = names.some((name) => hiddenNames.has(name)) &&
215
+ !names.some((name) => visibleNames.has(name));
216
+ if (!hiddenOnly)
217
+ continue;
218
+ esmToStrip.add(node);
219
+ // Visible names stay out of hiddenNames so the two sets stay disjoint.
220
+ for (const name of [...names, ...((_d = referencedNames.get(node)) !== null && _d !== void 0 ? _d : [])]) {
221
+ if (!hiddenNames.has(name) && !visibleNames.has(name)) {
222
+ hiddenNames.add(name);
223
+ changed = true;
224
+ }
225
+ }
226
+ }
227
+ }
228
+ tree.children = transformChildren(tree.children, esmToStrip);
131
229
  };