@mintlify/common 1.0.1110 → 1.0.1112

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.
@@ -7,6 +7,7 @@ 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 { jsx, toJs } from 'estree-util-to-js';
10
11
  import { walk } from 'estree-walker';
11
12
  import { visit } from 'unist-util-visit';
12
13
  import { removeFrontmatterFromAST } from '../../astUtils.js';
@@ -63,28 +64,85 @@ const replaceVariablesWithProps = (node, treeToInject, exportMap, snippetExportM
63
64
  const variableNameMap = {};
64
65
  const variablesMap = {};
65
66
  const propValues = getSnippetPropValues(node);
67
+ const passedProps = new Set(node.attributes.flatMap((attribute) => attribute.type === 'mdxJsxAttribute' ? [attribute.name] : []));
66
68
  replaceCodePlaceholdersWithProps(treeToInject, propValues);
69
+ const getUniqueName = (name) => {
70
+ const existing = variableNameMap[name];
71
+ if (existing != undefined)
72
+ return existing;
73
+ let id = 0;
74
+ let uniqueName = createUniqueVariableName(name, id);
75
+ while (exportMap[uniqueName]) {
76
+ id += 1;
77
+ uniqueName = createUniqueVariableName(name, id);
78
+ }
79
+ variablesMap[uniqueName] = { type: 'unknown', value: 'undefined' };
80
+ variableNameMap[name] = uniqueName;
81
+ return uniqueName;
82
+ };
83
+ /**
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`.)
88
+ */
89
+ const renamed = new WeakSet();
90
+ const scopeIdentifiers = (estree) => {
91
+ walk(estree, {
92
+ enter(jsNode, parent) {
93
+ if (jsNode.type !== 'Identifier')
94
+ return;
95
+ if (renamed.has(jsNode))
96
+ return;
97
+ if (snippetExportMap[jsNode.name] != undefined)
98
+ return;
99
+ // `JSON.stringify(...)`, `Math.max(...)`: a global is only a prop when the tag passes it
100
+ if (!passedProps.has(jsNode.name) && isGlobalName(jsNode.name))
101
+ return;
102
+ // `obj.prop` and `{ key: value }` — the property name is not a variable reference
103
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'MemberExpression' && parent.property === jsNode && !parent.computed)
104
+ return;
105
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'Property' && parent.key === jsNode && !parent.computed) {
106
+ if (!parent.shorthand)
107
+ return;
108
+ // `{ prop }` → `{ prop: prop_0 }`
109
+ parent.shorthand = false;
110
+ const value = Object.assign(Object.assign({}, jsNode), { name: getUniqueName(jsNode.name) });
111
+ renamed.add(value);
112
+ parent.value = value;
113
+ return;
114
+ }
115
+ jsNode.name = getUniqueName(jsNode.name);
116
+ renamed.add(jsNode);
117
+ },
118
+ });
119
+ return generate(estree);
120
+ };
121
+ const scopeSpreadAttribute = (estree) => {
122
+ scopeIdentifiers(estree);
123
+ const spread = getSpreadElement(estree);
124
+ return spread ? `...${generate(toProgram(spread.argument))}` : generate(estree);
125
+ };
67
126
  visit(treeToInject, (node) => {
68
- var _a;
127
+ var _a, _b, _c;
69
128
  if ((node.type === 'mdxTextExpression' || node.type === 'mdxFlowExpression') &&
70
129
  ((_a = node.data) === null || _a === void 0 ? void 0 : _a.estree)) {
71
- node.data.estree = walk(node.data.estree, {
72
- enter(jsNode) {
73
- if (jsNode.type === 'Identifier' && snippetExportMap[jsNode.name] == undefined) {
74
- let id = 0;
75
- let uniqueName = createUniqueVariableName(jsNode.name, id);
76
- while (exportMap[uniqueName]) {
77
- id += 1;
78
- uniqueName = createUniqueVariableName(jsNode.name, id);
79
- }
80
- // Replace node value with unique name
81
- node.value = node.value.replace(jsNode.name, uniqueName);
82
- variablesMap[uniqueName] = { type: 'unknown', value: 'undefined' };
83
- variableNameMap[jsNode.name] = uniqueName;
84
- jsNode.name = uniqueName;
85
- }
86
- },
87
- });
130
+ node.value = scopeIdentifiers(node.data.estree);
131
+ return;
132
+ }
133
+ // props referenced inside JSX attributes of the snippet, e.g. `<Card title={variant === "x" ? "a" : "b"}>`
134
+ if (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') {
135
+ for (const attribute of node.attributes) {
136
+ if (attribute.type === 'mdxJsxExpressionAttribute' && ((_b = attribute.data) === null || _b === void 0 ? void 0 : _b.estree)) {
137
+ attribute.value = scopeSpreadAttribute(attribute.data.estree);
138
+ }
139
+ else if (attribute.type === 'mdxJsxAttribute' &&
140
+ attribute.value &&
141
+ typeof attribute.value === 'object' &&
142
+ ((_c = attribute.value.data) === null || _c === void 0 ? void 0 : _c.estree)) {
143
+ attribute.value.value = scopeIdentifiers(attribute.value.data.estree);
144
+ }
145
+ }
88
146
  }
89
147
  });
90
148
  node.attributes.forEach((attribute) => {
@@ -100,7 +158,9 @@ const replaceVariablesWithProps = (node, treeToInject, exportMap, snippetExportM
100
158
  });
101
159
  const variableDeclarationNodes = [];
102
160
  Object.entries(variablesMap).map(([variable, value]) => {
103
- const statement = `export const ${variable} = ${value.type === 'string' ? `"${value.value}"` : value.value}`;
161
+ // JSON.stringify escapes quotes, backslashes and newlines so a prop value can never break
162
+ // out of the generated string literal
163
+ const statement = `export const ${variable} = ${value.type === 'string' ? JSON.stringify(value.value) : value.value}`;
104
164
  exportMap[variable] = statement;
105
165
  variableDeclarationNodes.push(...getAST(statement).children);
106
166
  });
@@ -109,6 +169,25 @@ const replaceVariablesWithProps = (node, treeToInject, exportMap, snippetExportM
109
169
  snippetNodesToInject: treeToInject.children,
110
170
  };
111
171
  };
172
+ const generate = (estree) => toJs(estree, { handlers: jsx }).value.replace(/;\s*$/, '');
173
+ const toProgram = (expression) => ({
174
+ type: 'Program',
175
+ sourceType: 'module',
176
+ body: [{ type: 'ExpressionStatement', expression }],
177
+ comments: [],
178
+ });
179
+ const getSpreadElement = (estree) => {
180
+ const [statement] = estree.body;
181
+ if ((statement === null || statement === void 0 ? void 0 : statement.type) !== 'ExpressionStatement')
182
+ return undefined;
183
+ const { expression } = statement;
184
+ if (expression.type !== 'ObjectExpression' || expression.properties.length !== 1)
185
+ return undefined;
186
+ const [property] = expression.properties;
187
+ return (property === null || property === void 0 ? void 0 : property.type) === 'SpreadElement' ? property : undefined;
188
+ };
189
+ const BROWSER_GLOBALS = new Set(['window', 'document', 'navigator', 'location', 'localStorage']);
190
+ const isGlobalName = (name) => name in globalThis || BROWSER_GLOBALS.has(name);
112
191
  const getSnippetPropValues = (node) => {
113
192
  const propValues = {};
114
193
  node.attributes.forEach((attribute) => {
package/dist/mdx/utils.js CHANGED
@@ -87,6 +87,7 @@ export const allowedComponents = [
87
87
  'Heading',
88
88
  'Info',
89
89
  'Icon',
90
+ 'MDX',
90
91
  'Link',
91
92
  'MDXContentController',
92
93
  'ResponseField',