@mintlify/common 1.0.1273 → 1.0.1275

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,10 +1,10 @@
1
1
  import { jsx, toJs } from 'estree-util-to-js';
2
2
  import { isObject } from '../../../types/guards.js';
3
- import { collectModuleWrites, collectPatternNames, forEachCodeChild, } from '../../estreeReferences.js';
3
+ import { collectDeclaredNames, collectModuleWrites, collectPatternNames, forEachCodeChild, visitReferences, } from '../../estreeReferences.js';
4
4
  import { getJsxEsmTree } from '../../snippets/getJsxEsmTree.js';
5
5
  import { BLOCK_LINK_LABEL, FIRST_PARTY_MARKDOWN_COMPONENT_SOURCE, } from './firstPartyMarkdownComponents.js';
6
6
  import { VISIBILITY_FOR_EXPECTED, isVisibilityAudience } from './remarkVisibilityForMarkdown.js';
7
- import { bindPattern, collectContextFromTree, EVAL_FAILED, evaluateStatic, identifierName, isNoOpSpreadValue, isStaticObject, nodeType, serializeStaticValue, unbindPattern, } from './staticEvaluator.js';
7
+ import { bindPattern, collectContextFromTree, EVAL_FAILED, evaluateStatic, identifierName, isNoOpSpreadValue, isStaticObject, nodeType, readsMarkdownChildren, serializeStaticValue, staticPropertyName, unbindPattern, } from './staticEvaluator.js';
8
8
  export const MAX_UNFOLD_OUTPUT_BYTES = 2000000;
9
9
  // Charged before each materialization so branching definition chains cannot run
10
10
  // exponential call volumes under the byte budget.
@@ -99,7 +99,12 @@ export function collectMarkdownComponentContext(tree) {
99
99
  const defs = new Map(getFirstPartyComponentDefs());
100
100
  for (const [name, def] of context.defs)
101
101
  defs.set(name, def);
102
- return { defs, moduleScope: context.moduleScope, literalScope: context.literalScope };
102
+ return {
103
+ defs,
104
+ moduleScope: context.moduleScope,
105
+ literalScope: context.literalScope,
106
+ declaredNames: context.declaredNames,
107
+ };
103
108
  }
104
109
  let firstPartyDefsCache;
105
110
  export function getFirstPartyComponentDefs() {
@@ -131,6 +136,49 @@ export const DROP_ELEMENTS = new Set([
131
136
  'template',
132
137
  'canvas',
133
138
  ]);
139
+ // Elements whose content is running text, so a component inside them stands for a word or phrase
140
+ const PHRASING_PARENTS = new Set([
141
+ 'p',
142
+ 'a',
143
+ 'span',
144
+ 'strong',
145
+ 'b',
146
+ 'em',
147
+ 'i',
148
+ 'code',
149
+ 'del',
150
+ 's',
151
+ 'small',
152
+ 'u',
153
+ 'sub',
154
+ 'sup',
155
+ 'mark',
156
+ 'abbr',
157
+ 'q',
158
+ 'cite',
159
+ 'label',
160
+ 'button',
161
+ 'h1',
162
+ 'h2',
163
+ 'h3',
164
+ 'h4',
165
+ 'h5',
166
+ 'h6',
167
+ 'summary',
168
+ 'figcaption',
169
+ ]);
170
+ // Form controls hold interactive state, not readable content
171
+ export const FORM_CONTROL_ELEMENTS = new Set([
172
+ 'input',
173
+ 'select',
174
+ 'textarea',
175
+ 'option',
176
+ 'optgroup',
177
+ 'datalist',
178
+ 'output',
179
+ 'progress',
180
+ 'meter',
181
+ ]);
134
182
  export const UNWRAP_BLOCK_ELEMENTS = new Set([
135
183
  'div',
136
184
  'section',
@@ -232,6 +280,17 @@ export function prefixBlockquoteLines(text) {
232
280
  .map((line) => (line.trim() === '' ? '>' : `> ${line}`))
233
281
  .join('\n');
234
282
  }
283
+ /** The first of `names` whose static attribute is a string with visible text. */
284
+ function firstTextAttribute(node, names, ctx) {
285
+ for (const attributeName of names) {
286
+ const value = findStaticAttribute(node, attributeName, ctx);
287
+ if (typeof value === 'string' && value.trim() !== '')
288
+ return value;
289
+ }
290
+ return undefined;
291
+ }
292
+ // Text an inline component shows when it has no children. `path` names a location, not a label.
293
+ const INLINE_TEXT_ATTRIBUTES = ['title', 'label', 'name', 'description', 'alt', 'aria-label'];
235
294
  function unfoldForeignComponent(node, ctx) {
236
295
  let children = serializeJsxChildren(node.children, ctx).trim();
237
296
  if (children === '') {
@@ -241,6 +300,19 @@ function unfoldForeignComponent(node, ctx) {
241
300
  else if (typeof childrenAttr === 'number')
242
301
  children = String(childrenAttr);
243
302
  }
303
+ // Inside running text the component stands for a word or phrase, not a block with a headline
304
+ if (ctx.inline === true) {
305
+ const attributeText = firstTextAttribute(node, INLINE_TEXT_ATTRIBUTES, ctx);
306
+ const text = children !== ''
307
+ ? children
308
+ : attributeText === undefined
309
+ ? ''
310
+ : escapeInterpolatedText(attributeText);
311
+ const inlineHref = findStaticAttribute(node, 'href', ctx);
312
+ if (text === '' || typeof inlineHref !== 'string' || inlineHref === '')
313
+ return text;
314
+ return `[${escapeLinkLabel(text)}](${markdownLinkDestination(inlineHref)})`;
315
+ }
244
316
  const description = findStaticAttribute(node, 'description', ctx);
245
317
  const alt = findStaticAttribute(node, 'alt', ctx);
246
318
  const body = children !== ''
@@ -547,6 +619,11 @@ function regenerateTag(node, name, children, ctx) {
547
619
  setAttribute(attrName.name, renderAttribute(attrName.name, resolved.value));
548
620
  continue;
549
621
  }
622
+ // An HTML attribute that cannot be resolved would print code, so it is left out
623
+ if (isIntrinsic) {
624
+ attrs.delete(attrName.name);
625
+ continue;
626
+ }
550
627
  const value = attribute.value;
551
628
  const source = nodeType(value) === 'JSXExpressionContainer' && isObject(value)
552
629
  ? serializeExpressionSource(value.expression)
@@ -562,13 +639,34 @@ function regenerateTag(node, name, children, ctx) {
562
639
  }
563
640
  return `<${name}${rendered}>${children}</${name}>`;
564
641
  }
642
+ /**
643
+ * Whether a sibling puts the element beside it inside running text: text on the same line, or an
644
+ * interpolated value. A line break between them means the element stands on its own line.
645
+ */
646
+ function touchesRunningText(sibling, side) {
647
+ if (!isObject(sibling))
648
+ return false;
649
+ if (sibling.type === 'JSXExpressionContainer') {
650
+ const type = nodeType(sibling.expression);
651
+ return type !== 'JSXEmptyExpression' && type !== 'JSXElement' && type !== 'JSXFragment';
652
+ }
653
+ if (sibling.type !== 'JSXText' || typeof sibling.value !== 'string')
654
+ return false;
655
+ if (sibling.value.trim() === '')
656
+ return false;
657
+ return side === 'before' ? !/\n[ \t]*$/.test(sibling.value) : !/^[ \t]*\n/.test(sibling.value);
658
+ }
565
659
  function serializeJsxChildren(children, ctx) {
566
660
  if (!Array.isArray(children))
567
661
  return '';
662
+ const kept = dropPairedDarkOnly(children, (node) => jsxClassName(node, ctx));
568
663
  let result = '';
569
- for (const child of dropPairedDarkOnly(children, (node) => jsxClassName(node, ctx))) {
570
- result += serializeJsxNode(child, ctx);
571
- }
664
+ kept.forEach((child, index) => {
665
+ const inline = ctx.inline === true ||
666
+ touchesRunningText(kept[index - 1], 'before') ||
667
+ touchesRunningText(kept[index + 1], 'after');
668
+ result += serializeJsxNode(child, inline === (ctx.inline === true) ? ctx : Object.assign(Object.assign({}, ctx), { inline }));
669
+ });
572
670
  return result;
573
671
  }
574
672
  function jsxClassName(node, ctx) {
@@ -649,10 +747,124 @@ function serializeJsxExpression(expression, ctx) {
649
747
  const text = String(value);
650
748
  return ctx.verbatim === true ? text : escapeInterpolatedText(text);
651
749
  }
652
- return '';
750
+ // A transformation of markdown children, such as uppercasing or truncating, cannot apply to
751
+ // their markdown; the children are kept as written so no words or links are lost
752
+ return producesMarkdownChildren(expression, ctx) ? ctx.childrenMarkdown : '';
753
+ }
754
+ // String methods whose result is a version of the text they are called on
755
+ const TEXT_TRANSFORMING_METHODS = new Set([
756
+ 'toUpperCase',
757
+ 'toLowerCase',
758
+ 'toLocaleUpperCase',
759
+ 'toLocaleLowerCase',
760
+ 'trim',
761
+ 'trimStart',
762
+ 'trimEnd',
763
+ 'slice',
764
+ 'substring',
765
+ 'replace',
766
+ 'replaceAll',
767
+ 'padStart',
768
+ 'padEnd',
769
+ 'concat',
770
+ 'normalize',
771
+ 'toString',
772
+ 'valueOf',
773
+ ]);
774
+ // Wrappers that leave the value of the expression inside them unchanged
775
+ const TRANSPARENT_WRAPPERS = new Set([
776
+ 'ParenthesizedExpression',
777
+ 'ChainExpression',
778
+ 'TSAsExpression',
779
+ 'TSSatisfiesExpression',
780
+ 'TSNonNullExpression',
781
+ 'TSTypeAssertion',
782
+ ]);
783
+ /**
784
+ * Whether `node` evaluates to a version of the component's markdown children: a text method on
785
+ * them, a template or JSX that renders them, or a branch that does. An expression that only
786
+ * inspects them, such as a count or a comparison, does not.
787
+ */
788
+ function producesMarkdownChildren(node, ctx) {
789
+ var _a;
790
+ let value = node;
791
+ while (isObject(value) &&
792
+ typeof value.type === 'string' &&
793
+ TRANSPARENT_WRAPPERS.has(value.type)) {
794
+ value = value.expression;
795
+ }
796
+ if (!isObject(value))
797
+ return false;
798
+ if (readsMarkdownChildren(value, ctx))
799
+ return true;
800
+ switch (value.type) {
801
+ case 'CallExpression': {
802
+ const callee = value.callee;
803
+ return (isObject(callee) &&
804
+ callee.type === 'MemberExpression' &&
805
+ TEXT_TRANSFORMING_METHODS.has((_a = staticPropertyName(callee)) !== null && _a !== void 0 ? _a : '') &&
806
+ producesMarkdownChildren(callee.object, ctx));
807
+ }
808
+ case 'ConditionalExpression':
809
+ return (producesMarkdownChildren(value.consequent, ctx) ||
810
+ producesMarkdownChildren(value.alternate, ctx));
811
+ case 'LogicalExpression':
812
+ return (producesMarkdownChildren(value.left, ctx) || producesMarkdownChildren(value.right, ctx));
813
+ case 'TemplateLiteral':
814
+ case 'JSXElement':
815
+ case 'JSXFragment':
816
+ return mentionsMarkdownChildren(value, ctx);
817
+ default:
818
+ return false;
819
+ }
820
+ }
821
+ /** Identifiers read as the object of a `.children` member, such as `props` in `props.children`. */
822
+ function collectChildrenMemberObjects(node, objects) {
823
+ if (Array.isArray(node)) {
824
+ for (const child of node)
825
+ collectChildrenMemberObjects(child, objects);
826
+ return;
827
+ }
828
+ if (!isObject(node))
829
+ return;
830
+ if (node.type === 'MemberExpression' &&
831
+ staticPropertyName(node) === 'children' &&
832
+ isObject(node.object) &&
833
+ node.object.type === 'Identifier') {
834
+ objects.add(node.object);
835
+ }
836
+ forEachCodeChild(node, (child) => collectChildrenMemberObjects(child, objects));
837
+ }
838
+ /**
839
+ * Whether `node` reads the component's own markdown children: the children parameter, or
840
+ * `.children` on its props or rest object. Property names, object keys, and shadowing bindings
841
+ * named `children` are not reads of it.
842
+ */
843
+ function mentionsMarkdownChildren(node, ctx) {
844
+ if (ctx.markdownChildren !== true)
845
+ return false;
846
+ const childrenObjects = new WeakSet();
847
+ collectChildrenMemberObjects(node, childrenObjects);
848
+ let found = false;
849
+ visitReferences(node, new Set(), {
850
+ reference: (identifier) => {
851
+ var _a, _b;
852
+ if (identifier.name === ctx.childrenName) {
853
+ found || (found = !((_b = (_a = ctx.failedProps) === null || _a === void 0 ? void 0 : _a.has('children')) !== null && _b !== void 0 ? _b : false));
854
+ return;
855
+ }
856
+ found || (found = childrenObjects.has(identifier) &&
857
+ (identifier.name === ctx.propsObjectName || identifier.name === ctx.restName));
858
+ },
859
+ });
860
+ return found;
653
861
  }
654
- function serializeJsxElement(node, ctx) {
862
+ function serializeJsxElement(node, elementCtx) {
655
863
  const name = getJsxElementName(node);
864
+ // The content of a phrasing element is running text; a block element starts its own flow
865
+ const ctx = name !== undefined && PHRASING_PARENTS.has(name)
866
+ ? Object.assign(Object.assign({}, elementCtx), { inline: true }) : name !== undefined && UNWRAP_BLOCK_ELEMENTS.has(name)
867
+ ? Object.assign(Object.assign({}, elementCtx), { inline: false }) : elementCtx;
656
868
  if (name === undefined)
657
869
  return '';
658
870
  if (isAriaHidden(node, ctx))
@@ -670,6 +882,8 @@ function serializeJsxElement(node, ctx) {
670
882
  if (isIntrinsic) {
671
883
  if (DROP_ELEMENTS.has(name))
672
884
  return accessibleFallback(node, ctx);
885
+ if (FORM_CONTROL_ELEMENTS.has(name))
886
+ return '';
673
887
  if (name === 'br')
674
888
  return '\n';
675
889
  if (name === 'hr')
@@ -1177,7 +1391,10 @@ function isResolvedReturn(expression, env) {
1177
1391
  return true;
1178
1392
  }
1179
1393
  /** A definition's scope for one usage: `base` plus its parameters bound from `props`. */
1180
- function bindComponentScope(paramInfo, base, props, failedProps, childrenMarkdown, effectiveChildren) {
1394
+ // Markdown a usage's children were serialized to, beyond plain words: links, emphasis, code,
1395
+ // escapes, HTML, or more than one line
1396
+ const MARKDOWN_SYNTAX = /[\\`*_[\]<>|~]|\n/;
1397
+ function bindComponentScope(paramInfo, base, props, failedProps, childrenMarkdown, effectiveChildren, declaredNames, markdownChildren = false) {
1181
1398
  const scope = new Map(base);
1182
1399
  if (paramInfo.propsObjectName !== undefined) {
1183
1400
  const propsObject = {};
@@ -1209,6 +1426,9 @@ function bindComponentScope(paramInfo, base, props, failedProps, childrenMarkdow
1209
1426
  failedProps,
1210
1427
  restName: paramInfo.restName,
1211
1428
  restFailedProps,
1429
+ declaredNames,
1430
+ childrenName: paramInfo.childrenName,
1431
+ markdownChildren,
1212
1432
  };
1213
1433
  // Supplied children are bound first, so later parameter defaults can read them
1214
1434
  if (childrenMarkdown !== '')
@@ -1262,31 +1482,6 @@ function bindComponentScope(paramInfo, base, props, failedProps, childrenMarkdow
1262
1482
  }
1263
1483
  return env;
1264
1484
  }
1265
- /** Every name a function body declares or binds, at any depth. */
1266
- function collectDeclaredNames(node, names = new Set()) {
1267
- if (Array.isArray(node)) {
1268
- for (const child of node)
1269
- collectDeclaredNames(child, names);
1270
- return names;
1271
- }
1272
- if (!isObject(node))
1273
- return names;
1274
- if (node.type === 'VariableDeclarator')
1275
- collectPatternNames(node.id, names);
1276
- if ((node.type === 'FunctionDeclaration' || node.type === 'ClassDeclaration') &&
1277
- isObject(node.id) &&
1278
- typeof node.id.name === 'string') {
1279
- names.add(node.id.name);
1280
- }
1281
- if (Array.isArray(node.params)) {
1282
- for (const param of node.params)
1283
- collectPatternNames(param, names);
1284
- }
1285
- if (node.type === 'CatchClause')
1286
- collectPatternNames(node.param, names);
1287
- forEachCodeChild(node, (child) => collectDeclaredNames(child, names));
1288
- return names;
1289
- }
1290
1485
  export function materializeComponent(def, name, props, childrenMarkdown, ctx, failedProps,
1291
1486
  // The static value of a body made of one expression, which `children` keeps over its markdown
1292
1487
  bodyValue, trusted) {
@@ -1310,10 +1505,10 @@ bodyValue, trusted) {
1310
1505
  const effectiveChildren = scopeChildren !== null && scopeChildren !== void 0 ? scopeChildren : childrenMarkdown;
1311
1506
  const paramInfo = analyzeParams(def.params);
1312
1507
  const named = new Set(paramInfo.bindings.map((binding) => binding.propName));
1313
- const env = bindComponentScope(paramInfo, ctx.moduleScope, props, failedProps, childrenMarkdown, effectiveChildren);
1508
+ const env = bindComponentScope(paramInfo, ctx.moduleScope, props, failedProps, childrenMarkdown, effectiveChildren, ctx.declaredNames, scopeChildren === undefined && MARKDOWN_SYNTAX.test(childrenMarkdown));
1314
1509
  // Props not supplied from trusted values are unknown here, so a default cannot stand in for them
1315
1510
  const untrusted = new Set([...props.keys()].filter((key) => (trusted === null || trusted === void 0 ? void 0 : trusted.props.has(key)) !== true));
1316
- const trustedEnvironment = bindComponentScope(paramInfo, trustedEnv(ctx).scope, (_a = trusted === null || trusted === void 0 ? void 0 : trusted.props) !== null && _a !== void 0 ? _a : new Map(), new Set([...((_b = trusted === null || trusted === void 0 ? void 0 : trusted.failedProps) !== null && _b !== void 0 ? _b : []), ...untrusted, ...(failedProps !== null && failedProps !== void 0 ? failedProps : [])]), '', '');
1511
+ const trustedEnvironment = bindComponentScope(paramInfo, trustedEnv(ctx).scope, (_a = trusted === null || trusted === void 0 ? void 0 : trusted.props) !== null && _a !== void 0 ? _a : new Map(), new Set([...((_b = trusted === null || trusted === void 0 ? void 0 : trusted.failedProps) !== null && _b !== void 0 ? _b : []), ...untrusted, ...(failedProps !== null && failedProps !== void 0 ? failedProps : [])]), '', '', ctx.declaredNames);
1317
1512
  // Locals may shadow trusted names with values that are not
1318
1513
  for (const local of collectDeclaredNames(def.body))
1319
1514
  trustedEnvironment.scope.delete(local);
@@ -1324,7 +1519,7 @@ bodyValue, trusted) {
1324
1519
  return '';
1325
1520
  if (!isResolvedReturn(returnExpression, env))
1326
1521
  return undefined;
1327
- const serializeContext = Object.assign(Object.assign({ defs: ctx.defs, moduleScope: ctx.moduleScope, literalScope: ctx.literalScope, stack: [...ctx.stack, def], budget: ctx.budget }, env), { trusted: trustedEnvironment, restCarriesChildren: !named.has('children'), childrenMarkdown, childrenName: paramInfo.childrenName });
1522
+ const serializeContext = Object.assign(Object.assign({ defs: ctx.defs, moduleScope: ctx.moduleScope, literalScope: ctx.literalScope, declaredNames: ctx.declaredNames, stack: [...ctx.stack, def], budget: ctx.budget }, env), { trusted: trustedEnvironment, restCarriesChildren: !named.has('children'), childrenMarkdown, childrenName: paramInfo.childrenName });
1328
1523
  return serializeJsxExpression(returnExpression, serializeContext);
1329
1524
  }
1330
1525
  export function collectUsageProps(node, ctx, failed) {
@@ -1334,6 +1529,7 @@ export function collectUsageProps(node, ctx, failed) {
1334
1529
  if (attribute.type === 'mdxJsxExpressionAttribute') {
1335
1530
  const spread = evaluateStatic(extractProgramExpression((_a = attribute.data) === null || _a === void 0 ? void 0 : _a.estree), {
1336
1531
  scope: ctx.moduleScope,
1532
+ declaredNames: ctx.declaredNames,
1337
1533
  });
1338
1534
  if (spread.ok && isStaticObject(spread.value)) {
1339
1535
  for (const [key, value] of Object.entries(spread.value)) {
@@ -1357,7 +1553,10 @@ export function collectUsageProps(node, ctx, failed) {
1357
1553
  }
1358
1554
  const estree = (_b = attribute.value.data) === null || _b === void 0 ? void 0 : _b.estree;
1359
1555
  const expression = extractProgramExpression(estree);
1360
- const evaluated = evaluateStatic(expression, { scope: ctx.moduleScope });
1556
+ const evaluated = evaluateStatic(expression, {
1557
+ scope: ctx.moduleScope,
1558
+ declaredNames: ctx.declaredNames,
1559
+ });
1361
1560
  if (evaluated.ok)
1362
1561
  setKnownProp(props, failed, attribute.name, evaluated.value);
1363
1562
  else
@@ -1404,6 +1603,7 @@ export function serializeExpressionJsx(expression, ctx) {
1404
1603
  defs: ctx.defs,
1405
1604
  moduleScope: ctx.moduleScope,
1406
1605
  literalScope: ctx.literalScope,
1606
+ declaredNames: ctx.declaredNames,
1407
1607
  stack: ctx.stack,
1408
1608
  budget: ctx.budget,
1409
1609
  scope: new Map(ctx.moduleScope),