@mintlify/scraping 4.0.1120 → 4.0.1122

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.1120",
3
+ "version": "4.0.1122",
4
4
  "description": "Scrape documentation frameworks to Mintlify docs",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -43,7 +43,7 @@
43
43
  "format:check": "oxfmt --check"
44
44
  },
45
45
  "dependencies": {
46
- "@mintlify/common": "1.0.1248",
46
+ "@mintlify/common": "1.0.1249",
47
47
  "fast-xml-parser": "5.7.3",
48
48
  "fs-extra": "11.1.1",
49
49
  "graphql": "16.11.0",
@@ -64,7 +64,7 @@
64
64
  "devDependencies": {
65
65
  "@mintlify/models": "0.0.374",
66
66
  "@mintlify/ts-config": "2.0.2",
67
- "@mintlify/validation": "0.1.916",
67
+ "@mintlify/validation": "0.1.917",
68
68
  "@tsconfig/recommended": "1.0.2",
69
69
  "@types/hast": "3.0.4",
70
70
  "@types/mdast": "4.0.4",
@@ -87,5 +87,5 @@
87
87
  "optional": true
88
88
  }
89
89
  },
90
- "gitHead": "8d6693e80052163587c46d12cb0e0b419dd149ad"
90
+ "gitHead": "a881933511e4a6a6a1b4e3cd0539361571d6491a"
91
91
  }
@@ -7,7 +7,18 @@ import { removeHastComments } from '../../utils/hastComments.js';
7
7
  import { hastToMdx, type RewriteLink } from '../convert.js';
8
8
  import type { SdkNavGroup, SdkPage, SdkReference } from '../types.js';
9
9
 
10
- type JavadocType = { pkg: string; name: string; file: string; slug: string };
10
+ type JavadocKind = 'interface' | 'class' | 'enum' | 'record' | 'exception' | 'error' | 'annotation';
11
+ type JavadocType = { pkg: string; name: string; file: string; slug: string; kind: JavadocKind };
12
+
13
+ const KINDS: { kind: JavadocKind; group: string; tag: string }[] = [
14
+ { kind: 'interface', group: 'Interfaces', tag: 'INTERFACE' },
15
+ { kind: 'class', group: 'Classes', tag: 'CLASS' },
16
+ { kind: 'enum', group: 'Enums', tag: 'ENUM' },
17
+ { kind: 'record', group: 'Records', tag: 'RECORD' },
18
+ { kind: 'exception', group: 'Exceptions', tag: 'EXCEPTION' },
19
+ { kind: 'error', group: 'Errors', tag: 'ERROR' },
20
+ { kind: 'annotation', group: 'Annotations', tag: 'ANNOTATION' },
21
+ ];
11
22
 
12
23
  const TYPE_NAME_PATTERN = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)*$/;
13
24
  const DROPPED_CLASSES = new Set([
@@ -24,12 +35,20 @@ export async function convertJavadoc(sourcePath: string): Promise<SdkReference>
24
35
  throw new Error(`No javadoc types found in ${sourcePath}`);
25
36
  }
26
37
  const slugByFile = new Map(types.map((type) => [type.file, type.slug]));
38
+ const kindsByPackage = new Map<string, Map<string, JavadocKind>>();
27
39
 
28
40
  const pages: SdkPage[] = [];
29
41
  const byPackage = new Map<string, JavadocType[]>();
30
42
  for (const type of types) {
31
43
  const html = await fse.readFile(path.join(sourcePath, type.file), 'utf8');
32
- pages.push(renderPage(type, html, slugByFile));
44
+ let packageKinds = kindsByPackage.get(type.pkg);
45
+ if (!packageKinds) {
46
+ packageKinds = await readPackageKinds(sourcePath, type.pkg);
47
+ kindsByPackage.set(type.pkg, packageKinds);
48
+ }
49
+ const page = renderPage(type, html, slugByFile, packageKinds.get(type.name));
50
+ type.kind = page.kind;
51
+ pages.push(page);
33
52
  const siblings = byPackage.get(type.pkg) ?? [];
34
53
  siblings.push(type);
35
54
  byPackage.set(type.pkg, siblings);
@@ -37,16 +56,85 @@ export async function convertJavadoc(sourcePath: string): Promise<SdkReference>
37
56
 
38
57
  const groups: SdkNavGroup[] = [...byPackage.entries()]
39
58
  .sort(([left], [right]) => left.localeCompare(right))
40
- .map(([pkg, members]) => ({
41
- group: pkg,
42
- pages: members
43
- .sort((left, right) => left.name.localeCompare(right.name))
44
- .map((member) => member.slug),
45
- }));
59
+ .map(([pkg, members]) => ({ group: pkg, pages: packageEntries(members) }));
46
60
 
47
61
  return { pages, groups };
48
62
  }
49
63
 
64
+ function packageEntries(members: JavadocType[]): (string | SdkNavGroup)[] {
65
+ const sorted = [...members].sort((left, right) => left.name.localeCompare(right.name));
66
+ const buckets = KINDS.map((entry) => ({
67
+ group: entry.group,
68
+ pages: sorted.filter((member) => member.kind === entry.kind).map((member) => member.slug),
69
+ })).filter((bucket) => bucket.pages.length > 0);
70
+ if (buckets.length <= 1) return sorted.map((member) => member.slug);
71
+ return buckets;
72
+ }
73
+
74
+ async function readPackageKinds(root: string, pkg: string): Promise<Map<string, JavadocKind>> {
75
+ const summaryPath = path.join(root, ...pkg.split('.'), 'package-summary.html');
76
+ if (!(await fse.pathExists(summaryPath))) return new Map();
77
+ const hast = htmlToHast(await fse.readFile(summaryPath, 'utf8'));
78
+ const kinds = new Map<string, JavadocKind>();
79
+ const record = (container: Element, kind: JavadocKind) => {
80
+ const cells = hasClass(container, 'col-first') || hasClass(container, 'colFirst');
81
+ visitElements(container, (el) => {
82
+ if (!cells && !hasClass(el, 'col-first') && !hasClass(el, 'colFirst')) return;
83
+ visitElements(el, (anchor) => recordAnchor(anchor, kind));
84
+ });
85
+ if (cells) visitElements(container, (anchor) => recordAnchor(anchor, kind));
86
+ };
87
+ const recordAnchor = (el: Element, kind: JavadocKind) => {
88
+ if (el.tagName !== 'a' || typeof el.properties.href !== 'string') return;
89
+ const href = el.properties.href.split(/[?#]/)[0] ?? '';
90
+ if (!href.endsWith('.html') || /^[a-z][a-z0-9+.-]*:/i.test(href)) return;
91
+ const name = path.posix.basename(href, '.html');
92
+ if (TYPE_NAME_PATTERN.test(name) && !kinds.has(name)) kinds.set(name, kind);
93
+ };
94
+
95
+ const kindByTab = new Map<string, JavadocKind>();
96
+ visitElements(hast, (el) => {
97
+ const id = el.properties?.id;
98
+ if (el.tagName !== 'button' || typeof id !== 'string' || !/^class-summary-tab\d+$/.test(id)) {
99
+ return;
100
+ }
101
+ const kind = kindFromLabel(textOf(el));
102
+ if (kind) kindByTab.set(id, kind);
103
+ });
104
+ if (kindByTab.size > 0) {
105
+ visitElements(hast, (el) => {
106
+ const tab = elementClasses(el).find((name) => kindByTab.has(name));
107
+ if (tab) record(el, kindByTab.get(tab) as JavadocKind);
108
+ });
109
+ return kinds;
110
+ }
111
+
112
+ visitElements(hast, (el) => {
113
+ if (el.tagName !== 'table') return;
114
+ const caption = findElement(el, (child) => child.tagName === 'caption');
115
+ const kind = caption ? kindFromLabel(textOf(caption)) : undefined;
116
+ if (kind) record(el, kind);
117
+ });
118
+ return kinds;
119
+ }
120
+
121
+ function kindFromLabel(label: string): JavadocKind | undefined {
122
+ const text = label
123
+ .replace(/\u00a0/g, ' ')
124
+ .replace(/\s+/g, ' ')
125
+ .trim()
126
+ .toLowerCase();
127
+ if (text.startsWith('all ')) return undefined;
128
+ if (text.startsWith('interface')) return 'interface';
129
+ if (text.startsWith('class')) return 'class';
130
+ if (text.startsWith('enum')) return 'enum';
131
+ if (text.startsWith('record')) return 'record';
132
+ if (text.startsWith('exception')) return 'exception';
133
+ if (text.startsWith('error')) return 'error';
134
+ if (text.startsWith('annotation')) return 'annotation';
135
+ return undefined;
136
+ }
137
+
50
138
  async function discoverTypes(root: string): Promise<JavadocType[]> {
51
139
  const entries = (await typesFromSearchIndex(root)) ?? (await typesFromPackageDirs(root));
52
140
  const seen = new Set<string>();
@@ -120,10 +208,16 @@ function makeType(pkg: string, name: string): JavadocType {
120
208
  name,
121
209
  file: `${pkg.split('.').join('/')}/${name}.html`,
122
210
  slug: `${pkg.replace(/\./g, '-')}/${name}`,
211
+ kind: 'class',
123
212
  };
124
213
  }
125
214
 
126
- function renderPage(type: JavadocType, html: string, slugByFile: Map<string, string>): SdkPage {
215
+ function renderPage(
216
+ type: JavadocType,
217
+ html: string,
218
+ slugByFile: Map<string, string>,
219
+ summaryKind: JavadocKind | undefined
220
+ ): SdkPage & { kind: JavadocKind } {
127
221
  const hast = htmlToHast(html);
128
222
  removeHastComments(hast);
129
223
  const main =
@@ -138,7 +232,8 @@ function renderPage(type: JavadocType, html: string, slugByFile: Map<string, str
138
232
  const details = findElement(main, (el) => hasClass(el, 'details'));
139
233
 
140
234
  const description = extractDescription(declaration);
141
- const tag = extractTag(main);
235
+ const kind = summaryKind ?? kindFromHeading(main);
236
+ const tag = KINDS.find((entry) => entry.kind === kind)?.tag ?? 'CLASS';
142
237
 
143
238
  const kept = [declaration, details].filter((node): node is Element => node !== undefined);
144
239
  const anchors = collectDetailAnchors(kept);
@@ -159,7 +254,7 @@ function renderPage(type: JavadocType, html: string, slugByFile: Map<string, str
159
254
  .join(`\`\`\`java\n${signature}\n\`\`\``);
160
255
  }
161
256
 
162
- return { slug: type.slug, title: type.name, description, tag, content };
257
+ return { slug: type.slug, title: type.name, description, tag, content, kind };
163
258
  }
164
259
 
165
260
  function makeHrefResolver(
@@ -269,13 +364,14 @@ function codifySignatures(node: Element): string[] {
269
364
  return signatures;
270
365
  }
271
366
 
272
- function extractTag(scope: Element | HastRoot): string {
367
+ function kindFromHeading(scope: Element | HastRoot): JavadocKind {
273
368
  const heading = findElement(scope, (el) => el.tagName === 'h1');
274
369
  const title = heading ? textOf(heading).trim() : '';
275
- if (title.startsWith('Annotation')) return 'ANNOTATION';
276
- if (title.startsWith('Enum')) return 'ENUM';
277
- if (title.startsWith('Interface')) return 'INTERFACE';
278
- return 'CLASS';
370
+ if (title.startsWith('Annotation')) return 'annotation';
371
+ if (title.startsWith('Enum')) return 'enum';
372
+ if (title.startsWith('Interface')) return 'interface';
373
+ if (title.startsWith('Record')) return 'record';
374
+ return 'class';
279
375
  }
280
376
 
281
377
  function extractDescription(declaration: Element | undefined): string | undefined {