@mintlify/scraping 4.0.1242 → 4.0.1243

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mintlify/scraping",
3
- "version": "4.0.1242",
3
+ "version": "4.0.1243",
4
4
  "description": "Scrape documentation frameworks to Mintlify docs",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -87,5 +87,5 @@
87
87
  "optional": true
88
88
  }
89
89
  },
90
- "gitHead": "121922c15ff85f7af9ee5f331edbe2e4c2967c17"
90
+ "gitHead": "b64533655063ddd4b082ddf392f252f23afe19ce"
91
91
  }
@@ -26,10 +26,14 @@ type DocfxItem = {
26
26
  remarks?: string;
27
27
  example?: string[];
28
28
  syntax?: DocfxSyntax;
29
+ inheritance?: string[];
30
+ implements?: string[];
29
31
  };
30
32
  type DocfxFile = { items?: DocfxItem[]; references?: { uid?: string; name?: string }[] };
31
33
  type TocNode = { uid?: string; type?: string; items?: TocNode[] };
32
34
 
35
+ const ROOT_BASE_TYPES = new Set(['System.Object', 'System.ValueType', 'System.Enum']);
36
+
33
37
  const PAGE_TAGS: Record<string, string> = {
34
38
  Class: 'CLASS',
35
39
  Interface: 'INTERFACE',
@@ -198,6 +202,7 @@ class DocfxRenderer {
198
202
  renderPage(item: DocfxItem): SdkPage {
199
203
  const lines: string[] = [this.prose(item.summary)];
200
204
  if (item.syntax?.content) lines.push(this.codeBlock(item.syntax.content));
205
+ lines.push(...this.renderHeritage(item));
201
206
  lines.push(this.prose(item.remarks));
202
207
  lines.push(...(item.example ?? []).map((example) => this.renderExample(example)));
203
208
 
@@ -268,6 +273,24 @@ class DocfxRenderer {
268
273
  return lines;
269
274
  }
270
275
 
276
+ private renderHeritage(item: DocfxItem): string[] {
277
+ const parent = item.inheritance?.at(-1);
278
+ return [
279
+ {
280
+ label: 'Extends',
281
+ uids: parent && !ROOT_BASE_TYPES.has(parent) ? [parent] : [],
282
+ },
283
+ { label: 'Implements', uids: item.implements ?? [] },
284
+ ]
285
+ .filter(({ uids }) => uids.length)
286
+ .map(
287
+ ({ label, uids }) =>
288
+ `**${label}:** ${uids
289
+ .map((uid) => linkedCode(this.typeTokens(uid)) ?? inlineCode(this.typeName(uid)))
290
+ .join(', ')}`
291
+ );
292
+ }
293
+
271
294
  private renderEnum(item: DocfxItem): string[] {
272
295
  const lines: string[] = ['## Members'];
273
296
  for (const member of this.members(item).filter((child) => child.type === 'Field')) {
@@ -286,15 +286,21 @@ class PhpdocRenderer {
286
286
  private renderHeritage(entry: Entry): string[] {
287
287
  const { element } = entry;
288
288
  const heritage = [
289
- element.extends ? `extends ${element.extends}` : '',
290
- element.implements?.length ? `implements ${element.implements.join(', ')}` : '',
291
- ].filter(Boolean);
289
+ { label: 'Extends', types: element.extends ? [element.extends] : [] },
290
+ { label: 'Implements', types: element.implements ?? [] },
291
+ ].filter(({ types }) => types.length);
292
292
  if (!heritage.length) return [];
293
293
  const modifiers = [
294
294
  element['@_abstract'] === 'true' ? 'abstract' : '',
295
295
  element['@_final'] === 'true' ? 'final' : '',
296
296
  ].filter(Boolean);
297
- return [this.codeBlock([...modifiers, entry.keyword, entry.name, ...heritage].join(' '))];
297
+ return [
298
+ this.codeBlock([...modifiers, entry.keyword, entry.name].join(' ')),
299
+ ...heritage.map(
300
+ ({ label, types }) =>
301
+ `**${label}:** ${types.map((type) => linkedCode(this.typeTokens(type)) ?? inlineCode(type)).join(', ')}`
302
+ ),
303
+ ];
298
304
  }
299
305
 
300
306
  private renderMethodBody(method: PhpMethod, depth: number): string[] {
@@ -1,3 +1,4 @@
1
+ import { cachedSlugify, slugify as headingSlug } from '@mintlify/common';
1
2
  import type { SdkSymbolKind } from '@mintlify/models';
2
3
  import fse from 'fs-extra';
3
4
  import path from 'node:path';
@@ -120,6 +121,16 @@ const SECTIONS: {
120
121
  const MAX_PLACEMENTS_PER_PAGE = 8;
121
122
  const MAX_DECLARATION_NAME_LENGTH = 512;
122
123
 
124
+ const FIELD_MEMBER_KINDS = new Set<number>([KIND.property, KIND.accessor]);
125
+
126
+ function memberAnchor(member: TypedocNode, inEnum: boolean): string | undefined {
127
+ if (inEnum || FIELD_MEMBER_KINDS.has(member.kind)) {
128
+ return cachedSlugify(`${inEnum ? 'member' : 'property'}-${member.name}`, { decamelize: true });
129
+ }
130
+ if (member.kind === KIND.method) return headingSlug(`${member.name}()`);
131
+ return undefined;
132
+ }
133
+
123
134
  const MEMBER_KINDS = new Set<number>([KIND.constructor, KIND.property, KIND.accessor, KIND.method]);
124
135
 
125
136
  const DEFAULT_GROUP_TITLE_BY_KIND = new Map<number, string>([
@@ -164,7 +175,20 @@ export async function convertTypedoc(sourcePath: string): Promise<SdkReference>
164
175
  }
165
176
  }
166
177
 
167
- const renderer = new TypedocRenderer(slugById);
178
+ const memberSlugById = new Map<number, string>();
179
+ for (const module of modules) {
180
+ for (const { node } of collectDeclarations(module)) {
181
+ const slug = slugById.get(node.id);
182
+ if (!slug) continue;
183
+ for (const child of node.children ?? []) {
184
+ if (child.flags?.isPrivate) continue;
185
+ const anchor = memberAnchor(child, node.kind === KIND.enum);
186
+ if (anchor) memberSlugById.set(child.id, `${slug}#${anchor}`);
187
+ }
188
+ }
189
+ }
190
+
191
+ const renderer = new TypedocRenderer(slugById, memberSlugById);
168
192
  const pages: SdkPage[] = [];
169
193
  const groups: SdkNavGroup[] = [];
170
194
  const moduleGroupById = new Map<number, PathNavGroup>();
@@ -353,7 +377,10 @@ function slugify(name: string): string {
353
377
  }
354
378
 
355
379
  class TypedocRenderer {
356
- constructor(private slugById: Map<number, string>) {}
380
+ constructor(
381
+ private slugById: Map<number, string>,
382
+ private memberSlugById = new Map<number, string>()
383
+ ) {}
357
384
 
358
385
  renderOverview(node: TypedocNode, slug: string, pages: SdkPage[], namespace?: string): SdkPage {
359
386
  const tree = parseSdkReadme(this.partsMarkdown(node.readme ?? []));
@@ -461,22 +488,15 @@ class TypedocRenderer {
461
488
  }
462
489
 
463
490
  private renderClassLike(node: TypedocNode): string[] {
464
- const lines: string[] = [];
465
- const heritage = [
466
- ...(node.extendedTypes?.length
467
- ? [`extends ${node.extendedTypes.map((t) => this.type(t)).join(', ')}`]
468
- : []),
469
- ...(node.implementedTypes?.length
470
- ? [`implements ${node.implementedTypes.map((t) => this.type(t)).join(', ')}`]
471
- : []),
472
- ];
473
- if (heritage.length) {
474
- lines.push(
475
- this.codeBlock(
476
- `${node.kind === KIND.class ? 'class' : 'interface'} ${node.name} ${heritage.join(' ')}`
477
- )
491
+ const lines = [
492
+ { label: 'Extends', types: node.extendedTypes },
493
+ { label: 'Implements', types: node.implementedTypes },
494
+ ]
495
+ .filter(({ types }) => types?.length)
496
+ .map(
497
+ ({ label, types }) =>
498
+ `**${label}:** ${(types ?? []).map((type) => this.linkedOrCode(type)).join(', ')}`
478
499
  );
479
- }
480
500
 
481
501
  const members = (node.children ?? []).filter((child) => !child.flags?.isPrivate);
482
502
  const layout = this.memberLayout(node, members);
@@ -559,7 +579,8 @@ class TypedocRenderer {
559
579
  property.name,
560
580
  type,
561
581
  property.flags?.isOptional === true,
562
- this.comment(property.comment ?? property.getSignature?.comment)
582
+ this.comment(property.comment ?? property.getSignature?.comment),
583
+ memberAnchor(property, false)
563
584
  )
564
585
  );
565
586
  }
@@ -578,7 +599,9 @@ class TypedocRenderer {
578
599
  member.name,
579
600
  member.type?.type === 'literal' ? JSON.stringify(member.type.value) : '',
580
601
  false,
581
- this.comment(member.comment)
602
+ this.comment(member.comment),
603
+ undefined,
604
+ memberAnchor(member, true)
582
605
  )
583
606
  );
584
607
  }
@@ -586,15 +609,11 @@ class TypedocRenderer {
586
609
  }
587
610
 
588
611
  private renderSignatures(node: TypedocNode, depth: number): string[] {
612
+ const signatures = node.signatures ?? [];
613
+ if (signatures.length > 1) return this.renderOverloads(signatures, depth);
589
614
  const lines: string[] = [];
590
- for (const signature of node.signatures ?? []) {
591
- const params = (signature.parameters ?? [])
592
- .map(
593
- (param) =>
594
- `${param.name}${param.flags?.isOptional || param.defaultValue !== undefined ? '?' : ''}: ${this.type(param.type)}`
595
- )
596
- .join(', ');
597
- lines.push(this.codeBlock(`${signature.name}(${params}): ${this.type(signature.type)}`));
615
+ for (const signature of signatures) {
616
+ lines.push(this.codeBlock(this.signatureLine(signature)));
598
617
  const comment = this.comment(signature.comment);
599
618
  if (comment) lines.push(comment);
600
619
  if (signature.parameters?.length) {
@@ -621,18 +640,91 @@ class TypedocRenderer {
621
640
  return lines;
622
641
  }
623
642
 
643
+ private renderOverloads(signatures: TypedocNode[], depth: number): string[] {
644
+ const lines = [
645
+ this.codeBlock(signatures.map((signature) => this.signatureLine(signature)).join('\n')),
646
+ ...distinct(signatures.map((signature) => this.comment(signature.comment))),
647
+ ];
648
+
649
+ const names = distinct(
650
+ signatures.flatMap((signature) => (signature.parameters ?? []).map((param) => param.name))
651
+ );
652
+ if (names.length) lines.push(detailHeading('Parameters', depth));
653
+ for (const name of names) {
654
+ const params = signatures.map((signature) =>
655
+ signature.parameters?.find((param) => param.name === name)
656
+ );
657
+ const present = params.filter((param) => param !== undefined);
658
+ const optional = params.some(
659
+ (param) => !param || param.flags?.isOptional === true || param.defaultValue !== undefined
660
+ );
661
+ const body = distinct(present.map((param) => this.comment(param.comment))).join('\n\n');
662
+ const types = this.distinctTypes(present.map((param) => param.type));
663
+ const [only] = types;
664
+ if (types.length === 1) {
665
+ lines.push(this.typeField(name, only, optional, body));
666
+ continue;
667
+ }
668
+ const variants = types.map((type) => `- ${this.linkedOrCode(type)}`).join('\n');
669
+ lines.push(
670
+ responseField(
671
+ name,
672
+ types.map((type) => this.type(type)).join(' | '),
673
+ optional,
674
+ [`**Type:** one of\n\n${variants}`, body].filter(Boolean).join('\n\n')
675
+ )
676
+ );
677
+ }
678
+
679
+ const returnTypes = this.distinctTypes(signatures.map((signature) => signature.type)).filter(
680
+ (type) => this.type(type) !== 'void'
681
+ );
682
+ if (returnTypes.length) {
683
+ lines.push(
684
+ detailHeading('Returns', depth),
685
+ returnTypes.map((type) => this.linkedOrCode(type)).join(' | '),
686
+ ...distinct(
687
+ signatures.map((signature) => {
688
+ const returns = signature.comment?.blockTags?.find((tag) => tag.tag === '@returns');
689
+ return returns ? this.parts(returns.content) : '';
690
+ })
691
+ )
692
+ );
693
+ }
694
+ return lines;
695
+ }
696
+
697
+ private distinctTypes(types: (TypedocType | undefined)[]): (TypedocType | undefined)[] {
698
+ return [...new Map(types.map((type) => [this.linkedOrCode(type), type])).values()];
699
+ }
700
+
701
+ private signatureLine(signature: TypedocNode): string {
702
+ const params = (signature.parameters ?? [])
703
+ .map(
704
+ (param) =>
705
+ `${param.name}${param.flags?.isOptional || param.defaultValue !== undefined ? '?' : ''}: ${this.type(param.type)}`
706
+ )
707
+ .join(', ');
708
+ return `${signature.name}(${params}): ${this.type(signature.type)}`;
709
+ }
710
+
711
+ private linkedOrCode(type?: TypedocType): string {
712
+ return this.linkedType(type) ?? inlineCode(this.type(type));
713
+ }
714
+
624
715
  private typeField(
625
716
  name: string,
626
717
  type: TypedocType | undefined,
627
718
  optional: boolean,
628
- body?: string
719
+ body?: string,
720
+ id?: string
629
721
  ): string {
630
722
  const tokens = this.typeTokens(type);
631
723
  const [only] = tokens;
632
724
  const typeHref = tokens.length === 1 && only?.href ? `/${only.href}` : undefined;
633
725
  const linked = typeHref ? undefined : this.linkedType(type);
634
726
  const content = [linked && `**Type:** ${linked}`, body].filter(Boolean).join('\n\n');
635
- return responseField(name, this.type(type), optional, content, typeHref);
727
+ return responseField(name, this.type(type), optional, content, typeHref, id);
636
728
  }
637
729
 
638
730
  private codeBlock(code: string): string {
@@ -661,9 +753,11 @@ class TypedocRenderer {
661
753
  return parts
662
754
  .map((part) => {
663
755
  if (part.kind === 'inline-tag') {
664
- if (typeof part.target === 'number' && this.slugById.has(part.target)) {
665
- return `[${part.text}](/${this.slugById.get(part.target)})`;
666
- }
756
+ const slug =
757
+ typeof part.target === 'number'
758
+ ? (this.slugById.get(part.target) ?? this.memberSlugById.get(part.target))
759
+ : undefined;
760
+ if (slug) return `[${part.text}](/${slug})`;
667
761
  if (typeof part.target === 'string') return `[${part.text}](${part.target})`;
668
762
  return `\`${part.text}\``;
669
763
  }
@@ -790,3 +884,7 @@ function headingText(title: unknown): string {
790
884
  function detailHeading(title: string, depth: number): string {
791
885
  return depth <= MAX_HEADING_DEPTH ? `${'#'.repeat(depth)} ${title}` : `**${title}**`;
792
886
  }
887
+
888
+ function distinct(items: string[]): string[] {
889
+ return [...new Set(items)].filter(Boolean);
890
+ }