@mintlify/common 1.0.1116 → 1.0.1118

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.
@@ -1,6 +1,6 @@
1
1
  import type { Root } from 'mdast';
2
2
  /**
3
- * Unwraps paragraph children inside JSX heading elements (h1–h6).
3
+ * Unwraps paragraph children inside JSX heading elements (h1–h6 and `Heading`).
4
4
  *
5
5
  * The custom-ID preprocessor emits headings like `<h2 id="x">\nText\n</h2>`,
6
6
  * and MDX parses the text on its own line as a paragraph block. This plugin
@@ -1,7 +1,8 @@
1
1
  import { visit } from 'unist-util-visit';
2
2
  import { ALL_HEADING_NAMES } from '../../preprocessCustomHeadingIds.js';
3
+ const UNWRAPPED_HEADING_NAMES = new Set([...ALL_HEADING_NAMES, 'Heading']);
3
4
  /**
4
- * Unwraps paragraph children inside JSX heading elements (h1–h6).
5
+ * Unwraps paragraph children inside JSX heading elements (h1–h6 and `Heading`).
5
6
  *
6
7
  * The custom-ID preprocessor emits headings like `<h2 id="x">\nText\n</h2>`,
7
8
  * and MDX parses the text on its own line as a paragraph block. This plugin
@@ -10,7 +11,7 @@ import { ALL_HEADING_NAMES } from '../../preprocessCustomHeadingIds.js';
10
11
  export const remarkUnwrapJsxHeadings = () => (tree) => {
11
12
  visit(tree, 'mdxJsxFlowElement', (node) => {
12
13
  var _a;
13
- if (!ALL_HEADING_NAMES.includes((_a = node.name) !== null && _a !== void 0 ? _a : ''))
14
+ if (!UNWRAPPED_HEADING_NAMES.has((_a = node.name) !== null && _a !== void 0 ? _a : ''))
14
15
  return;
15
16
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
17
  node.children = node.children.flatMap((child) => child.type === 'paragraph' && 'children' in child ? child.children : [child]);
@@ -7,6 +7,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
+ import { Parser } from 'acorn';
11
+ import acornJsx from 'acorn-jsx';
10
12
  import { jsx, toJs } from 'estree-util-to-js';
11
13
  import { walk } from 'estree-walker';
12
14
  import { visit } from 'unist-util-visit';
@@ -81,13 +83,23 @@ const replaceVariablesWithProps = (node, treeToInject, exportMap, snippetExportM
81
83
  return uniqueName;
82
84
  };
83
85
  /**
84
- * Rename every free identifier in an expression's estree to its unique name and
85
- * regenerate the expression source from the estree so the two never disagree.
86
- * (Replacing the first textual occurrence only — the previous behaviour — corrupted any
87
- * expression that referenced the same prop twice, e.g. `a === "x" ? 1 : a === "y" ? 2 : 3`.)
86
+ * Rename every free identifier in an expression to its unique name.
87
+ *
88
+ * The renames are spliced into the expression's own source text by position, so everything
89
+ * else — parentheses, indentation, an inline `style={{ … }}` object, the markdown inside an
90
+ * `<MDX>` fragment — stays byte-for-byte as the author wrote it. Regenerating the text from the
91
+ * estree instead pretty-prints nested objects across several lines at column 0, which turns into
92
+ * lazy lines inside a list once an `<MDX>` fragment is re-parsed as markdown. The source is
93
+ * re-parsed with acorn because the mdast estree carries document offsets while `value` has its
94
+ * per-line indent stripped, so the two no longer line up.
95
+ *
96
+ * The estree is renamed in place as well so it never disagrees with the text. Only when the text
97
+ * cannot be parsed on its own is it regenerated from the estree (the previous behaviour).
98
+ * Replacing the first textual occurrence only — the behaviour before that — corrupted any
99
+ * expression that referenced the same prop twice, e.g. `a === "x" ? 1 : a === "y" ? 2 : 3`.
88
100
  */
89
101
  const renamed = new WeakSet();
90
- const scopeIdentifiers = (estree) => {
102
+ const renameIdentifiers = (estree, edits) => {
91
103
  walk(estree, {
92
104
  enter(jsNode, parent) {
93
105
  if (jsNode.type !== 'Identifier')
@@ -102,20 +114,29 @@ const replaceVariablesWithProps = (node, treeToInject, exportMap, snippetExportM
102
114
  // `obj.prop` and `{ key: value }` — the property name is not a variable reference
103
115
  if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'MemberExpression' && parent.property === jsNode && !parent.computed)
104
116
  return;
117
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'Property' && parent.shorthand && parent.value === jsNode)
118
+ return;
105
119
  if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'Property' && parent.key === jsNode && !parent.computed) {
106
120
  if (!parent.shorthand)
107
121
  return;
108
122
  // `{ prop }` → `{ prop: prop_0 }`
123
+ const uniqueName = getUniqueName(jsNode.name);
124
+ edits === null || edits === void 0 ? void 0 : edits.push(Object.assign(Object.assign({}, positionOf(jsNode)), { text: `${jsNode.name}: ${uniqueName}` }));
109
125
  parent.shorthand = false;
110
- const value = Object.assign(Object.assign({}, jsNode), { name: getUniqueName(jsNode.name) });
126
+ const value = Object.assign(Object.assign({}, jsNode), { name: uniqueName });
111
127
  renamed.add(value);
112
128
  parent.value = value;
113
129
  return;
114
130
  }
115
- jsNode.name = getUniqueName(jsNode.name);
131
+ const uniqueName = getUniqueName(jsNode.name);
132
+ edits === null || edits === void 0 ? void 0 : edits.push(Object.assign(Object.assign({}, positionOf(jsNode)), { text: uniqueName }));
133
+ jsNode.name = uniqueName;
116
134
  renamed.add(jsNode);
117
135
  },
118
136
  });
137
+ };
138
+ const scopeIdentifiers = (estree) => {
139
+ renameIdentifiers(estree);
119
140
  return generate(estree);
120
141
  };
121
142
  const scopeSpreadAttribute = (estree) => {
@@ -123,24 +144,39 @@ const replaceVariablesWithProps = (node, treeToInject, exportMap, snippetExportM
123
144
  const spread = getSpreadElement(estree);
124
145
  return spread ? `...${generate(toProgram(spread.argument))}` : generate(estree);
125
146
  };
147
+ /** `{value}` of an expression or attribute; `...rest` of a spread attribute when `spread`. */
148
+ const scopeSource = (source, estree, spread = false) => {
149
+ const text = spread ? `{${source}}` : source;
150
+ const parsed = parseExpression(text);
151
+ if (!parsed)
152
+ return spread ? scopeSpreadAttribute(estree) : scopeIdentifiers(estree);
153
+ const edits = [];
154
+ renameIdentifiers(parsed, edits);
155
+ renameIdentifiers(estree);
156
+ let result = text;
157
+ for (const edit of edits.sort((a, b) => b.start - a.start)) {
158
+ result = result.slice(0, edit.start) + edit.text + result.slice(edit.end);
159
+ }
160
+ return spread ? result.slice(1, -1) : result;
161
+ };
126
162
  visit(treeToInject, (node) => {
127
163
  var _a, _b, _c;
128
164
  if ((node.type === 'mdxTextExpression' || node.type === 'mdxFlowExpression') &&
129
165
  ((_a = node.data) === null || _a === void 0 ? void 0 : _a.estree)) {
130
- node.value = scopeIdentifiers(node.data.estree);
166
+ node.value = scopeSource(node.value, node.data.estree);
131
167
  return;
132
168
  }
133
169
  // props referenced inside JSX attributes of the snippet, e.g. `<Card title={variant === "x" ? "a" : "b"}>`
134
170
  if (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') {
135
171
  for (const attribute of node.attributes) {
136
172
  if (attribute.type === 'mdxJsxExpressionAttribute' && ((_b = attribute.data) === null || _b === void 0 ? void 0 : _b.estree)) {
137
- attribute.value = scopeSpreadAttribute(attribute.data.estree);
173
+ attribute.value = scopeSource(attribute.value, attribute.data.estree, true);
138
174
  }
139
175
  else if (attribute.type === 'mdxJsxAttribute' &&
140
176
  attribute.value &&
141
177
  typeof attribute.value === 'object' &&
142
178
  ((_c = attribute.value.data) === null || _c === void 0 ? void 0 : _c.estree)) {
143
- attribute.value.value = scopeIdentifiers(attribute.value.data.estree);
179
+ attribute.value.value = scopeSource(attribute.value.value, attribute.value.data.estree);
144
180
  }
145
181
  }
146
182
  }
@@ -170,6 +206,30 @@ const replaceVariablesWithProps = (node, treeToInject, exportMap, snippetExportM
170
206
  };
171
207
  };
172
208
  const generate = (estree) => toJs(estree, { handlers: jsx }).value.replace(/;\s*$/, '');
209
+ const JSXParser = Parser.extend(acornJsx());
210
+ /**
211
+ * Parse `text` as a single expression; undefined when it is not one on its own. `preserveParens`
212
+ * so `( … )` around the whole expression — common when a snippet wraps a ternary in `{( … )}` —
213
+ * yields a node spanning the entire text; without it acorn returns the inner expression, whose
214
+ * `end` stops before the closing `)`, and the text would wrongly be treated as unparseable.
215
+ */
216
+ const parseExpression = (text) => {
217
+ try {
218
+ const expression = JSXParser.parseExpressionAt(text, 0, {
219
+ ecmaVersion: 'latest',
220
+ sourceType: 'module',
221
+ preserveParens: true,
222
+ });
223
+ return text.slice(expression.end).trim() === '' ? expression : undefined;
224
+ }
225
+ catch (_a) {
226
+ return undefined;
227
+ }
228
+ };
229
+ const positionOf = (node) => {
230
+ const { start, end } = node;
231
+ return { start, end };
232
+ };
173
233
  const toProgram = (expression) => ({
174
234
  type: 'Program',
175
235
  sourceType: 'module',